home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / app / gradient.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-05-08  |  159.2 KB  |  6,376 lines

  1. /* The GIMP -- an image manipulation program
  2.  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
  3.  *
  4.  * Gradient editor module copyight (C) 1996-1997 Federico Mena Quintero
  5.  * federico@nuclecu.unam.mx
  6.  *
  7.  * This program is free software; you can redistribute it and/or modify
  8.  * it under the terms of the GNU General Public License as published by
  9.  * the Free Software Foundation; either version 2 of the License, or
  10.  * (at your option) any later version.
  11.  *
  12.  * This program is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURIGHTE.  See the
  15.  * GNU General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with this program; if not, write to the Free Software
  19.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  20.  */
  21.  
  22. /* Special thanks to:
  23.  *
  24.  * Luis Albarran (luis4@mindspring.com) - Nice UI suggestions
  25.  *
  26.  * Miguel de Icaza (miguel@nuclecu.unam.mx) - Pop-up menu suggestion
  27.  *
  28.  * Marcelo Malheiros (malheiro@dca.fee.unicamp.br) - many, many
  29.  * suggestions, nice gradient files
  30.  *
  31.  * Adam Moss (adam@uunet.pipex.com) - idea for the hint bar
  32.  *
  33.  * Everyone on #gimp - many suggestions
  34.  */
  35.  
  36. /* TODO:
  37.  *
  38.  * - Fix memory leaks: grad_free_gradient_editor() and any others
  39.  * which I may have missed.
  40.  *
  41.  * - Add all of Marcelo's neat suggestions:
  42.  *   - Hue rotate, saturation, brightness, contrast.
  43.  *
  44.  * - Better handling of bogus gradient files and inconsistent
  45.  *   segments.  Do not loop indefinitely in seg_get_segment_at() if
  46.  *   there is a missing segment between two others.
  47.  *
  48.  * - Add a Gradient brush mode (color changes as you move it).
  49.  */
  50.  
  51. #include "config.h"
  52.  
  53. #include <stdio.h>
  54. #include <stdlib.h>
  55. #include <string.h>
  56. #ifdef HAVE_UNISTD_H
  57. #include <unistd.h>
  58. #endif
  59.  
  60. #include <gtk/gtk.h>
  61.  
  62. #include "apptypes.h"
  63.  
  64. #include "appenv.h"
  65. #include "cursorutil.h"
  66. #include "datafiles.h"
  67. #include "errors.h"
  68. #include "gimpcontext.h"
  69. #include "gimpdnd.h"
  70. #include "gimprc.h"
  71. #include "gimpui.h"
  72. #include "gradient.h"
  73. #include "gradientP.h"
  74. #include "gradient_header.h"
  75. #include "gradient_select.h"
  76.  
  77. #include "libgimp/gimpenv.h"
  78. #include "libgimp/gimplimits.h"
  79. #include "libgimp/gimpmath.h"
  80. #include "libgimp/gimpcolorspace.h"
  81.  
  82. #include "libgimp/gimpintl.h"
  83.  
  84. #include "pixmaps/zoom_in.xpm"
  85. #include "pixmaps/zoom_out.xpm"
  86.  
  87.  
  88. /***** Magic numbers *****/
  89.  
  90. #define EPSILON 1e-10
  91.  
  92. #define GRAD_LIST_WIDTH  300
  93. #define GRAD_LIST_HEIGHT  80
  94.  
  95. #define GRAD_SCROLLBAR_STEP_SIZE 0.05
  96. #define GRAD_SCROLLBAR_PAGE_SIZE 0.75
  97.  
  98. #define GRAD_PREVIEW_WIDTH  600
  99. #define GRAD_PREVIEW_HEIGHT  64
  100. #define GRAD_CONTROL_HEIGHT  10
  101.  
  102. #define GRAD_COLOR_BOX_WIDTH  24
  103. #define GRAD_COLOR_BOX_HEIGHT 16
  104.  
  105. #define GRAD_NUM_COLORS 10
  106.  
  107. #define GRAD_MOVE_TIME 150 /* ms between mouse click and detection of movement in gradient control */
  108.  
  109. #define GRAD_PREVIEW_EVENT_MASK (GDK_EXPOSURE_MASK | \
  110.                                  GDK_LEAVE_NOTIFY_MASK | \
  111.                  GDK_POINTER_MOTION_MASK | \
  112.                                  GDK_POINTER_MOTION_HINT_MASK | \
  113.                  GDK_BUTTON_PRESS_MASK | \
  114.                                  GDK_BUTTON_RELEASE_MASK)
  115.  
  116. #define GRAD_CONTROL_EVENT_MASK (GDK_EXPOSURE_MASK | \
  117.                  GDK_LEAVE_NOTIFY_MASK | \
  118.                  GDK_POINTER_MOTION_MASK | \
  119.                  GDK_POINTER_MOTION_HINT_MASK | \
  120.                  GDK_BUTTON_PRESS_MASK | \
  121.                  GDK_BUTTON_RELEASE_MASK | \
  122.                  GDK_BUTTON1_MOTION_MASK)
  123.  
  124. enum
  125. {
  126.   GRAD_UPDATE_GRADIENT = 1 << 0,
  127.   GRAD_UPDATE_PREVIEW  = 1 << 1,
  128.   GRAD_UPDATE_CONTROL  = 1 << 2,
  129.   GRAD_RESET_CONTROL   = 1 << 3
  130. };
  131.  
  132. /* Gradient editor type */
  133.  
  134. typedef enum
  135. {
  136.   GRAD_DRAG_NONE = 0,
  137.   GRAD_DRAG_LEFT,
  138.   GRAD_DRAG_MIDDLE,
  139.   GRAD_DRAG_ALL
  140. } control_drag_mode_t;
  141.  
  142. typedef struct
  143. {
  144.   GtkWidget *shell;
  145.   GdkGC     *gc;
  146.   GtkWidget *hint_label;
  147.   GtkWidget *clist;
  148.   GtkWidget *scrollbar;
  149.   GtkWidget *preview;
  150.   GtkWidget *control;
  151.  
  152.   /*  Zoom and scrollbar  */
  153.   guint      zoom_factor;
  154.   GtkObject *scroll_data;
  155.  
  156.   /*  Instant update  */
  157.   gboolean   instant_update;
  158.  
  159.   /*  Gradient preview  */
  160.   guchar    *preview_rows[2]; /* For caching redraw info */
  161.   gint       preview_last_x;
  162.   gboolean   preview_button_down;
  163.  
  164.   /*  Gradient control  */
  165.   GdkPixmap           *control_pixmap;
  166.   grad_segment_t      *control_drag_segment; /* Segment which is being dragged */
  167.   grad_segment_t      *control_sel_l;        /* Left segment of selection */
  168.   grad_segment_t      *control_sel_r;        /* Right segment of selection */
  169.   control_drag_mode_t  control_drag_mode;    /* What is being dragged? */
  170.   guint32              control_click_time;   /* Time when mouse was pressed */
  171.   gboolean             control_compress;     /* Compressing/expanding handles */
  172.   gint                 control_last_x;       /* Last mouse position when dragging */
  173.   gdouble              control_last_gx;      /* Last position (wrt gradient) when dragging */
  174.   gdouble              control_orig_pos;     /* Original click position when dragging */
  175.  
  176.   GtkWidget *control_main_popup;              /* Popup menu */
  177.   GtkWidget *control_blending_label;          /* Blending function label */
  178.   GtkWidget *control_coloring_label;          /* Coloring type label */
  179.   GtkWidget *control_split_m_label;           /* Split at midpoint label */
  180.   GtkWidget *control_split_u_label;           /* Split uniformly label */
  181.   GtkWidget *control_delete_menu_item;        /* Delete menu item */
  182.   GtkWidget *control_delete_label;            /* Delete label */
  183.   GtkWidget *control_recenter_label;          /* Re-center label */
  184.   GtkWidget *control_redistribute_label;      /* Re-distribute label */
  185.   GtkWidget *control_flip_label;              /* Flip label */
  186.   GtkWidget *control_replicate_label;         /* Replicate label */
  187.   GtkWidget *control_blend_colors_menu_item;  /* Blend colors menu item */
  188.   GtkWidget *control_blend_opacity_menu_item; /* Blend opacity menu item */
  189.   GtkWidget *control_left_load_popup;         /* Left endpoint load menu */
  190.   GtkWidget *control_left_save_popup;         /* Left endpoint save menu */
  191.   GtkWidget *control_right_load_popup;        /* Right endpoint load menu */
  192.   GtkWidget *control_right_save_popup;        /* Right endpoint save menu */
  193.   GtkWidget *control_blending_popup;          /* Blending function menu */
  194.   GtkWidget *control_coloring_popup;          /* Coloring type menu */
  195.   GtkWidget *control_sel_ops_popup;           /* Selection ops menu */
  196.  
  197.   GtkAccelGroup *accel_group;
  198.  
  199.   /*  Blending and coloring menus  */
  200.   GtkWidget *control_blending_items[5 + 1]; /* Add 1 for the "Varies" item */
  201.   GtkWidget *control_coloring_items[3 + 1];
  202.  
  203.   /*  Split uniformly dialog  */
  204.   gint split_parts;
  205.  
  206.   /*  Replicate dialog  */
  207.   gint replicate_times;
  208.  
  209.   /*  Saved colors  */
  210.   struct
  211.   {
  212.     gdouble r, g, b, a;
  213.   } saved_colors[GRAD_NUM_COLORS];
  214.  
  215.   GtkWidget *left_load_color_boxes[GRAD_NUM_COLORS + 3];
  216.   GtkWidget *left_load_labels[GRAD_NUM_COLORS + 3];
  217.  
  218.   GtkWidget *left_save_color_boxes[GRAD_NUM_COLORS];
  219.   GtkWidget *left_save_labels[GRAD_NUM_COLORS];
  220.  
  221.   GtkWidget *right_load_color_boxes[GRAD_NUM_COLORS + 3];
  222.   GtkWidget *right_load_labels[GRAD_NUM_COLORS + 3];
  223.  
  224.   GtkWidget *right_save_color_boxes[GRAD_NUM_COLORS];
  225.   GtkWidget *right_save_labels[GRAD_NUM_COLORS];
  226.  
  227.   /*  Color dialogs  */
  228.   GtkWidget      *left_color_preview;
  229.   grad_segment_t *left_saved_segments;
  230.   gboolean        left_saved_dirty;
  231.  
  232.   GtkWidget      *right_color_preview;
  233.   grad_segment_t *right_saved_segments;
  234.   gboolean        right_saved_dirty;
  235. } GradientEditor;
  236.  
  237. /***** Local functions *****/
  238.  
  239. static gint    gradient_editor_clist_button_press (GtkWidget       *widget,
  240.                            GdkEventButton  *bevent,
  241.                            gpointer         data);
  242.  
  243. static gradient_t * gradient_editor_drag_gradient (GtkWidget       *widget,
  244.                            gpointer         data);
  245.  
  246. static void       gradient_editor_drop_gradient   (GtkWidget       *widget,
  247.                            gradient_t      *gradient,
  248.                            gpointer         data);
  249.  
  250. /* Gradient editor functions */
  251.  
  252. static GtkWidget * ed_create_button               (gchar           *label,
  253.                            gchar           *help_data,
  254.                            GtkSignalFunc    signal_func,
  255.                            gpointer         data);
  256.  
  257. static void      ed_fetch_foreground              (gdouble         *fg_r,
  258.                            gdouble         *fg_g,
  259.                            gdouble         *fg_b,
  260.                            gdouble         *fg_a);
  261. static void      ed_update_editor                 (gint             flags);
  262.  
  263. static void      ed_set_hint                      (gchar           *str);
  264.  
  265.  
  266. static void      ed_list_item_update              (GtkWidget       *widget, 
  267.                            gint             row,
  268.                            gint             column,
  269.                            GdkEventButton  *event,
  270.                            gpointer         data);
  271.  
  272. static void      ed_initialize_saved_colors       (void);
  273.  
  274. /* Main dialog button callbacks & functions */
  275.  
  276. static void      ed_new_gradient_callback         (GtkWidget       *widget,
  277.                            gpointer         data);
  278. static void      ed_do_new_gradient_callback      (GtkWidget       *widget,
  279.                            gchar           *gradient_name,
  280.                            gpointer         data);
  281.  
  282. static void      ed_copy_gradient_callback        (GtkWidget       *widget,
  283.                            gpointer         data);
  284. static void      ed_do_copy_gradient_callback     (GtkWidget       *widget,
  285.                            gchar           *gradient_name,
  286.                            gpointer         data);
  287.  
  288. static void      ed_delete_gradient_callback      (GtkWidget       *widget,
  289.                            gpointer         data);
  290. static void      ed_do_delete_gradient_callback   (GtkWidget       *widget,
  291.                            gboolean         delete,
  292.                            gpointer         data);
  293.  
  294. static void      ed_rename_gradient_callback      (GtkWidget       *widget,
  295.                            gpointer         data);
  296. static void      ed_do_rename_gradient_callback   (GtkWidget       *widget,
  297.                            gchar           *gradient_name,
  298.                            gpointer         data);
  299.  
  300. static void      ed_save_pov_callback             (GtkWidget       *widget,
  301.                            gpointer         data);
  302. static void      ed_do_save_pov_callback          (GtkWidget       *widget,
  303.                            gpointer         data);
  304. static void      ed_cancel_save_pov_callback      (GtkWidget       *widget,
  305.                            gpointer         data);
  306. static gint      ed_delete_save_pov_callback      (GtkWidget       *widget,
  307.                            GdkEvent        *event,
  308.                            gpointer         data);
  309.  
  310. static void      ed_refresh_grads_callback        (GtkWidget       *widget,
  311.                            gpointer         data);
  312. static void      ed_close_callback                (GtkWidget       *widget,
  313.                            gpointer         data);
  314.  
  315. /* Zoom, scrollbar & instant update callbacks */
  316.  
  317. static void      ed_scrollbar_update              (GtkAdjustment   *adjustment,
  318.                            gpointer         data);
  319. static void      ed_zoom_all_callback             (GtkWidget       *widget,
  320.                            gpointer         data);
  321. static void      ed_zoom_out_callback             (GtkWidget       *widget,
  322.                            gpointer         data);
  323. static void      ed_zoom_in_callback              (GtkWidget       *widget,
  324.                            gpointer         data);
  325. static void      ed_instant_update_update         (GtkWidget       *widget,
  326.                            gpointer         data);
  327.  
  328. /* Gradient preview functions */
  329.  
  330. static gint      preview_events                   (GtkWidget       *widget,
  331.                            GdkEvent        *event,
  332.                            gpointer         data);
  333. static void      preview_set_hint                 (gint             x);
  334.  
  335. static void      preview_set_foreground           (gint             x);
  336. static void      preview_set_background           (gint             x);
  337.  
  338. static void      gradient_update                  (void);
  339. static void      preview_update                   (gboolean         recalculate);
  340. static void      preview_fill_image               (gint             width,
  341.                            gint             height,
  342.                            gdouble          left,
  343.                            gdouble          right);
  344.  
  345. /* Gradient control functions */
  346.  
  347. static gint      control_events                   (GtkWidget       *widget,
  348.                            GdkEvent        *event,
  349.                            gpointer         data);
  350. static void      control_do_hint                  (gint             x,
  351.                            gint             y);
  352. static void      control_button_press             (gint             x,
  353.                            gint             y,
  354.                            guint            button,
  355.                            guint            state);
  356. static gboolean  control_point_in_handle          (gint             x,
  357.                            gint             y,
  358.                            grad_segment_t  *seg,
  359.                            control_drag_mode_t handle);
  360. static void      control_select_single_segment    (grad_segment_t  *seg);
  361. static void      control_extend_selection         (grad_segment_t  *seg,
  362.                            gdouble          pos);
  363. static void      control_motion                   (gint             x);
  364.  
  365. static void      control_compress_left            (grad_segment_t  *range_l,
  366.                            grad_segment_t  *range_r,
  367.                            grad_segment_t  *drag_seg,
  368.                            gdouble          pos);
  369. static void      control_compress_range           (grad_segment_t  *range_l,
  370.                            grad_segment_t  *range_r,
  371.                            gdouble          new_l,
  372.                            gdouble          new_r);
  373.  
  374. static double    control_move                     (grad_segment_t  *range_l,
  375.                            grad_segment_t  *range_r,
  376.                            gdouble          delta);
  377.  
  378. /* Control update/redraw functions */
  379.  
  380. static void      control_update                   (gboolean         recalculate);
  381. static void      control_draw                     (GdkPixmap       *pixmap,
  382.                            gint             width,
  383.                            gint             height,
  384.                            gdouble          left,
  385.                            gdouble          right);
  386. static void      control_draw_normal_handle       (GdkPixmap       *pixmap,
  387.                            gdouble          pos,
  388.                            gint             height);
  389. static void      control_draw_middle_handle       (GdkPixmap       *pixmap,
  390.                            gdouble          pos,
  391.                            gint             height);
  392. static void      control_draw_handle              (GdkPixmap       *pixmap,
  393.                            GdkGC           *border_gc,
  394.                            GdkGC           *fill_gc,
  395.                            gint             xpos,
  396.                            gint             height);
  397.  
  398. static gint      control_calc_p_pos               (gdouble          pos);
  399. static gdouble   control_calc_g_pos               (gint             pos);
  400.  
  401. /* Control popup functions */
  402.  
  403. static void      cpopup_create_main_menu          (void);
  404. static void      cpopup_do_popup                  (void);
  405.  
  406. static GtkWidget * cpopup_create_color_item           (GtkWidget  **color_box,
  407.                                GtkWidget  **label);
  408. static GtkWidget * cpopup_create_menu_item_with_label (gchar       *str,
  409.                                GtkWidget  **label);
  410.  
  411. static void      cpopup_adjust_menus              (void);
  412. static void      cpopup_adjust_blending_menu      (void);
  413. static void      cpopup_adjust_coloring_menu      (void);
  414. static void      cpopup_check_selection_params    (gint            *equal_blending,
  415.                            gint            *equal_coloring);
  416.  
  417. static void      cpopup_render_color_box          (GtkPreview      *preview,
  418.                            gdouble          r,
  419.                            gdouble          g,
  420.                            gdouble          b,
  421.                            gdouble          a);
  422.  
  423. static GtkWidget * cpopup_create_load_menu        (GtkWidget      **color_boxes,
  424.                            GtkWidget      **labels,
  425.                            gchar           *label1,
  426.                            gchar           *label2,
  427.                            GtkSignalFunc    callback,
  428.                            gchar            accel_key_0,
  429.                            guint8           accel_mods_0,
  430.                            gchar            accel_key_1,
  431.                            guint8           accel_mods_1,
  432.                            gchar            accel_key_2,
  433.                            guint8           accel_mods_2);
  434. static GtkWidget * cpopup_create_save_menu        (GtkWidget      **color_boxes,
  435.                            GtkWidget      **labels,
  436.                            GtkSignalFunc    callback);
  437.  
  438. static void      cpopup_update_saved_color        (gint             n,
  439.                            gdouble          r,
  440.                            gdouble          g,
  441.                            gdouble          b,
  442.                            gdouble          a);
  443.  
  444. static void      cpopup_load_left_callback        (GtkWidget       *widget,
  445.                            gpointer         data);
  446. static void      cpopup_save_left_callback        (GtkWidget       *widget,
  447.                            gpointer         data);
  448. static void      cpopup_load_right_callback       (GtkWidget       *widget,
  449.                            gpointer         data);
  450. static void      cpopup_save_right_callback       (GtkWidget       *widget,
  451.                            gpointer         data);
  452.  
  453. static void      cpopup_set_color_selection_color (GtkColorSelection *cs,
  454.                            gdouble            r,
  455.                            gdouble            g,
  456.                            gdouble            b,
  457.                            gdouble            a);
  458. static void      cpopup_get_color_selection_color (GtkColorSelection *cs,
  459.                            gdouble           *r,
  460.                            gdouble           *g,
  461.                            gdouble           *b,
  462.                            gdouble           *a);
  463.  
  464. static grad_segment_t * cpopup_save_selection     (void);
  465. static void             cpopup_free_selection     (grad_segment_t  *seg);
  466. static void             cpopup_replace_selection  (grad_segment_t  *replace_seg);
  467.  
  468. /* ----- */
  469.  
  470. static void   cpopup_create_color_dialog          (gchar           *title,
  471.                            double           r,
  472.                            double           g,
  473.                            double           b,
  474.                            double           a,
  475.                            GtkSignalFunc    color_changed_callback,
  476.                            GtkSignalFunc    ok_callback,
  477.                            GtkSignalFunc    cancel_callback,
  478.                            GtkSignalFunc    delete_callback);
  479.  
  480. static void   cpopup_set_left_color_callback      (GtkWidget       *widget,
  481.                            gpointer         data);
  482. static void   cpopup_left_color_changed           (GtkWidget       *widget,
  483.                            gpointer         data);
  484. static void   cpopup_left_color_dialog_ok         (GtkWidget       *widget,
  485.                            gpointer         data);
  486. static void   cpopup_left_color_dialog_cancel     (GtkWidget       *widget,
  487.                            gpointer         data);
  488. static gint   cpopup_left_color_dialog_delete     (GtkWidget       *widget,
  489.                            GdkEvent        *event,
  490.                            gpointer         data);
  491.  
  492. static void   cpopup_set_right_color_callback     (GtkWidget       *widget,
  493.                            gpointer         data);
  494. static void   cpopup_right_color_changed          (GtkWidget       *widget,
  495.                            gpointer         data);
  496. static void   cpopup_right_color_dialog_ok        (GtkWidget       *widget,
  497.                            gpointer         data);
  498. static void   cpopup_right_color_dialog_cancel    (GtkWidget       *widget,
  499.                            gpointer         data);
  500. static gint   cpopup_right_color_dialog_delete    (GtkWidget       *widget,
  501.                            GdkEvent        *event,
  502.                            gpointer         data);
  503.  
  504. /* ----- */
  505.  
  506. static GtkWidget * cpopup_create_blending_menu    (void);
  507. static void        cpopup_blending_callback       (GtkWidget       *widget,
  508.                            gpointer         data);
  509. static GtkWidget * cpopup_create_coloring_menu    (void);
  510. static void        cpopup_coloring_callback       (GtkWidget       *widget,
  511.                            gpointer         data);
  512.  
  513. /* ----- */
  514.  
  515. static void  cpopup_split_midpoint_callback       (GtkWidget       *widget,
  516.                            gpointer         data);
  517. static void  cpopup_split_midpoint                (grad_segment_t  *lseg,
  518.                            grad_segment_t **newl,
  519.                            grad_segment_t **newr);
  520.  
  521. static void  cpopup_split_uniform_callback        (GtkWidget       *widget,
  522.                            gpointer         data);
  523. static void  cpopup_split_uniform_scale_update    (GtkAdjustment   *adjustment,
  524.                            gpointer         data);
  525. static void  cpopup_split_uniform_split_callback  (GtkWidget       *widget,
  526.                            gpointer         data);
  527. static void  cpopup_split_uniform_cancel_callback (GtkWidget       *widget,
  528.                            gpointer         data);
  529. static void  cpopup_split_uniform                 (grad_segment_t  *lseg,
  530.                            gint             parts,
  531.                            grad_segment_t **newl,
  532.                            grad_segment_t **newr);
  533.  
  534. static void  cpopup_delete_callback               (GtkWidget       *widget,
  535.                            gpointer         data);
  536. static void  cpopup_recenter_callback             (GtkWidget       *widget,
  537.                            gpointer         data);
  538. static void  cpopup_redistribute_callback         (GtkWidget       *widget,
  539.                            gpointer         data);
  540.  
  541. /* Control popup -> Selection operations functions */
  542.  
  543. static GtkWidget * cpopup_create_sel_ops_menu     (void);
  544.  
  545. static void      cpopup_flip_callback             (GtkWidget       *widget,
  546.                            gpointer         data);
  547.  
  548. static void      cpopup_replicate_callback        (GtkWidget       *widget,
  549.                            gpointer         data);
  550. static void      cpopup_replicate_scale_update    (GtkAdjustment   *widget,
  551.                            gpointer         data);
  552. static void      cpopup_do_replicate_callback     (GtkWidget       *widget,
  553.                            gpointer         data);
  554. static void      cpopup_replicate_cancel_callback (GtkWidget       *widget,
  555.                            gpointer         data);
  556.  
  557. static void      cpopup_blend_colors              (GtkWidget       *widget,
  558.                            gpointer         data);
  559. static void      cpopup_blend_opacity             (GtkWidget       *widget,
  560.                            gpointer         data);
  561.  
  562. /* Blend function */
  563.  
  564. static void      cpopup_blend_endpoints           (gdouble          r0,
  565.                            gdouble          g0,
  566.                            gdouble          b0,
  567.                            gdouble          a0,
  568.                            gdouble          r1,
  569.                            gdouble          g1,
  570.                            gdouble          b1,
  571.                            gdouble          a1,
  572.                            gint             blend_colors,
  573.                            gint             blend_opacity);
  574.  
  575. /* Gradient functions */
  576.  
  577. static gradient_t     * grad_new_gradient             (void);
  578. static void             grad_free_gradient            (gradient_t *grad);
  579. static void             grad_free_gradients           (void);
  580. static void             grad_load_gradient            (gchar      *filename);
  581. static void             grad_save_gradient            (gradient_t *grad,
  582.                                gchar      *filename);
  583. static void             grad_save_all                 (gboolean    need_free);
  584.  
  585. static gradient_t     * grad_create_default_gradient  (void);
  586.  
  587. static gint             grad_insert_in_gradients_list (gradient_t *grad);
  588.  
  589. static void             grad_dump_gradient            (gradient_t *grad,
  590.                                FILE       *file);
  591. static void     gradients_list_uniquefy_gradient_name (gradient_t *gradient);
  592.  
  593.  
  594. /* Segment functions */
  595.  
  596. static grad_segment_t * seg_new_segment        (void);
  597. static void             seg_free_segment       (grad_segment_t       *seg);
  598. static void             seg_free_segments      (grad_segment_t       *seg);
  599.  
  600. static grad_segment_t * seg_get_segment_at     (gradient_t           *grad,
  601.                         gdouble               pos);
  602. static grad_segment_t * seg_get_last_segment   (grad_segment_t       *seg);
  603. static void             seg_get_closest_handle (gradient_t           *grad,
  604.                         gdouble               pos,
  605.                         grad_segment_t      **seg,
  606.                         control_drag_mode_t  *handle);
  607.  
  608. /* Calculation functions */
  609.  
  610. static gdouble   calc_linear_factor            (gdouble  middle,
  611.                         gdouble  pos);
  612. static gdouble   calc_curved_factor            (gdouble  middle,
  613.                         gdouble  pos);
  614. static gdouble   calc_sine_factor              (gdouble  middle,
  615.                         gdouble  pos);
  616. static gdouble   calc_sphere_increasing_factor (gdouble  middle,
  617.                         gdouble  pos);
  618. static gdouble   calc_sphere_decreasing_factor (gdouble  middle,
  619.                         gdouble  pos);
  620.  
  621. /* Files and paths functions */
  622.  
  623. static gchar   * build_user_filename           (gchar   *name,
  624.                         gchar   *path_str);
  625.  
  626.  
  627. /***** Global variables *****/
  628.  
  629. GSList * gradients_list = NULL; /* The list of gradients */
  630. gint     num_gradients  = 0;
  631.  
  632. /***** Local variables *****/
  633.  
  634. static GdkColor         black;
  635. static gradient_t     * curr_gradient     = NULL;
  636. static gradient_t     * dnd_gradient      = NULL;
  637. static GradientEditor * g_editor          = NULL;
  638.  
  639. static gradient_t     * standard_gradient = NULL;
  640.  
  641. static const gchar *blending_types[] =
  642. {
  643.   N_("Linear"),
  644.   N_("Curved"),
  645.   N_("Sinusoidal"),
  646.   N_("Spherical (increasing)"),
  647.   N_("Spherical (decreasing)")
  648. };
  649.  
  650. static const gchar *coloring_types[] =
  651. {
  652.   N_("Plain RGB"),
  653.   N_("HSV (counter-clockwise hue)"),
  654.   N_("HSV (clockwise hue)")
  655. };
  656.  
  657. /*  dnd stuff  */
  658. static GtkTargetEntry gradient_target_table[] =
  659. {
  660.   GIMP_TARGET_GRADIENT
  661. };
  662. static guint n_gradient_targets = (sizeof (gradient_target_table) /
  663.                    sizeof (gradient_target_table[0]));
  664.  
  665. /***** Public functions *****/
  666.  
  667. void
  668. gradients_init (gint no_data)
  669. {
  670.   if (gradients_list)
  671.     gradients_free ();
  672.  
  673.   if (gradient_path != NULL && !no_data)
  674.     datafiles_read_directories (gradient_path, grad_load_gradient, 0);
  675.  
  676.   gimp_context_refresh_gradients ();
  677. }
  678.  
  679. void
  680. gradients_free (void)
  681. {
  682.   grad_free_gradients ();
  683. }
  684.  
  685. gradient_t *
  686. gradients_get_standard_gradient (void)
  687. {
  688.   if (! standard_gradient)
  689.     {
  690.       standard_gradient = grad_create_default_gradient ();
  691.       standard_gradient->name     = g_strdup ("Standard");
  692.       standard_gradient->filename = NULL;
  693.       standard_gradient->dirty    = FALSE;
  694.     }
  695.  
  696.   return standard_gradient;
  697. }
  698.  
  699. gradient_t *
  700. gradient_list_get_gradient (GSList *list,
  701.                 gchar  *name)
  702. {
  703.   gradient_t *gradient;
  704.  
  705.   if (name == NULL)
  706.     return NULL;
  707.  
  708.   for (; list; list = g_slist_next (list))
  709.     {
  710.       gradient = (gradient_t *) list->data;
  711.  
  712.       if (strcmp (gradient->name, name) == 0)
  713.     return gradient;
  714.     }
  715.  
  716.   return NULL;
  717. }
  718.  
  719. gint
  720. gradient_list_get_gradient_index (GSList     *list,
  721.                   gradient_t *gradient)
  722. {
  723.   gradient_t *cmp_gradient;
  724.   gint        index;
  725.  
  726.   for (index = 0; list; list = g_slist_next (list), index++)
  727.     {
  728.       cmp_gradient = (gradient_t *) list->data;
  729.  
  730.       if (cmp_gradient == gradient)
  731.     return index;
  732.     }
  733.  
  734.   return -1;
  735. }
  736.  
  737. /*****/
  738.  
  739. void
  740. gradient_get_color_at (gradient_t *gradient,
  741.                gdouble     pos,
  742.                gdouble    *r,
  743.                gdouble    *g,
  744.                gdouble    *b,
  745.                gdouble    *a)
  746. {
  747.   gdouble         factor = 0.0;
  748.   grad_segment_t *seg;
  749.   gdouble         seg_len, middle;
  750.   gdouble         h0, s0, v0;
  751.   gdouble         h1, s1, v1;
  752.  
  753.   /* if there is no gradient return a totally transparent black */
  754.   if (gradient == NULL) 
  755.     {
  756.       r = 0; g = 0; b = 0; a = 0;
  757.       return;
  758.     }
  759.  
  760.   if (pos < 0.0)
  761.     pos = 0.0;
  762.   else if (pos > 1.0)
  763.     pos = 1.0;
  764.  
  765.   seg = seg_get_segment_at (gradient, pos);
  766.  
  767.   seg_len = seg->right - seg->left;
  768.  
  769.   if (seg_len < EPSILON)
  770.     {
  771.       middle = 0.5;
  772.       pos    = 0.5;
  773.     }
  774.   else
  775.     {
  776.       middle = (seg->middle - seg->left) / seg_len;
  777.       pos    = (pos - seg->left) / seg_len;
  778.     }
  779.  
  780.   switch (seg->type)
  781.     {
  782.     case GRAD_LINEAR:
  783.       factor = calc_linear_factor (middle, pos);
  784.       break;
  785.  
  786.     case GRAD_CURVED:
  787.       factor = calc_curved_factor (middle, pos);
  788.       break;
  789.  
  790.     case GRAD_SINE:
  791.       factor = calc_sine_factor (middle, pos);
  792.       break;
  793.  
  794.     case GRAD_SPHERE_INCREASING:
  795.       factor = calc_sphere_increasing_factor (middle, pos);
  796.       break;
  797.  
  798.     case GRAD_SPHERE_DECREASING:
  799.       factor = calc_sphere_decreasing_factor (middle, pos);
  800.       break;
  801.  
  802.     default:
  803.       grad_dump_gradient (gradient, stderr);
  804.       gimp_fatal_error ("gradient_get_color_at(): Unknown gradient type %d",
  805.             (int) seg->type);
  806.       break;
  807.     }
  808.  
  809.   /* Calculate color components */
  810.  
  811.   *a = seg->a0 + (seg->a1 - seg->a0) * factor;
  812.  
  813.   if (seg->color == GRAD_RGB)
  814.     {
  815.       *r = seg->r0 + (seg->r1 - seg->r0) * factor;
  816.       *g = seg->g0 + (seg->g1 - seg->g0) * factor;
  817.       *b = seg->b0 + (seg->b1 - seg->b0) * factor;
  818.     }
  819.   else
  820.     {
  821.       h0 = seg->r0;
  822.       s0 = seg->g0;
  823.       v0 = seg->b0;
  824.  
  825.       h1 = seg->r1;
  826.       s1 = seg->g1;
  827.       v1 = seg->b1;
  828.  
  829.       gimp_rgb_to_hsv_double (&h0, &s0, &v0);
  830.       gimp_rgb_to_hsv_double (&h1, &s1, &v1);
  831.  
  832.       s0 = s0 + (s1 - s0) * factor;
  833.       v0 = v0 + (v1 - v0) * factor;
  834.  
  835.       switch (seg->color)
  836.     {
  837.     case GRAD_HSV_CCW:
  838.       if (h0 < h1)
  839.         {
  840.           h0 = h0 + (h1 - h0) * factor;
  841.         }
  842.       else
  843.         {
  844.           h0 = h0 + (1.0 - (h0 - h1)) * factor;
  845.           if (h0 > 1.0)
  846.         h0 -= 1.0;
  847.         }
  848.       break;
  849.  
  850.     case GRAD_HSV_CW:
  851.       if (h1 < h0)
  852.         {
  853.           h0 = h0 - (h0 - h1) * factor;
  854.         }
  855.       else
  856.         {
  857.           h0 = h0 - (1.0 - (h1 - h0)) * factor;
  858.           if (h0 < 0.0)
  859.         h0 += 1.0;
  860.         }
  861.       break;
  862.  
  863.     default:
  864.       grad_dump_gradient (gradient, stderr);
  865.       gimp_fatal_error ("gradient_get_color_at(): Unknown coloring mode %d",
  866.                 (int) seg->color);
  867.       break;
  868.     }
  869.  
  870.       *r = h0;
  871.       *g = s0;
  872.       *b = v0;
  873.  
  874.       gimp_hsv_to_rgb_double (r, g, b);
  875.     }
  876. }
  877.  
  878. /***** The main gradient editor dialog *****/
  879.  
  880. void 
  881. gradient_editor_create (void)
  882. {
  883.   GtkWidget   *vbox;
  884.   GtkWidget   *hbox;
  885.   GtkWidget   *gvbox;
  886.   GtkWidget   *button;
  887.   GtkWidget   *frame;
  888.   GtkWidget   *scrolled_win;
  889.   GdkColormap *colormap;
  890.   gchar       *titles[2];
  891.   gint         column_width;
  892.   gint         select_pos;
  893.   gint         i;
  894.  
  895.   /* If the editor already exists, just show it */
  896.   if (g_editor)
  897.     {
  898.       if (! GTK_WIDGET_VISIBLE (g_editor->shell))
  899.     gtk_widget_show (g_editor->shell);
  900.       else
  901.     gdk_window_raise (g_editor->shell->window);
  902.  
  903.       return;
  904.     }
  905.  
  906.   g_editor = g_new (GradientEditor, 1);
  907.  
  908.   /* Shell and main vbox */
  909.   g_editor->shell =
  910.     gimp_dialog_new (_("Gradient Editor"), "gradient_editor",
  911.              gimp_standard_help_func,
  912.              "dialogs/gradient_editor/gradient_editor.html",
  913.              GTK_WIN_POS_NONE,
  914.              FALSE, TRUE, FALSE,
  915.  
  916.              _("Refresh"), ed_refresh_grads_callback,
  917.              NULL, NULL, NULL, FALSE, FALSE,
  918.              _("Close"), ed_close_callback,
  919.              NULL, NULL, NULL, TRUE, TRUE,
  920.  
  921.              NULL);
  922.  
  923.   vbox = gtk_vbox_new (FALSE, 4);
  924.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 4);
  925.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (g_editor->shell)->vbox), vbox);
  926.   gtk_widget_show (vbox);
  927.  
  928.   /* Gradients list box */
  929.   hbox = gtk_hbox_new (FALSE, 4);
  930.   gtk_box_pack_start (GTK_BOX (vbox), hbox, TRUE, TRUE, 0);
  931.   gtk_widget_show (hbox);
  932.  
  933.   /* clist preview of gradients */
  934.   scrolled_win = gtk_scrolled_window_new (NULL, NULL);
  935.   gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
  936.                   GTK_POLICY_AUTOMATIC,
  937.                   GTK_POLICY_ALWAYS);
  938.   gtk_box_pack_start (GTK_BOX (hbox), scrolled_win, TRUE, TRUE, 0); 
  939.   gtk_widget_show (scrolled_win);
  940.  
  941.   titles[0] = _("Gradient");
  942.   titles[1] = _("Name");
  943.   g_editor->clist = gtk_clist_new_with_titles (2, titles);
  944.   gtk_clist_set_shadow_type (GTK_CLIST (g_editor->clist), GTK_SHADOW_IN);
  945.   gtk_clist_set_selection_mode (GTK_CLIST (g_editor->clist),
  946.                 GTK_SELECTION_BROWSE);
  947.   gtk_clist_set_row_height (GTK_CLIST (g_editor->clist), 18);
  948.   gtk_clist_set_use_drag_icons (GTK_CLIST (g_editor->clist), FALSE);
  949.   gtk_clist_column_titles_passive (GTK_CLIST (g_editor->clist));
  950.   gtk_container_add (GTK_CONTAINER (scrolled_win), g_editor->clist);
  951.  
  952.   column_width =
  953.     MAX (50, gtk_clist_optimal_column_width (GTK_CLIST (g_editor->clist), 0));
  954.   gtk_clist_set_column_min_width (GTK_CLIST (g_editor->clist), 0, 50);
  955.   gtk_clist_set_column_width (GTK_CLIST (g_editor->clist), 0, column_width);
  956.  
  957.   gtk_widget_show (g_editor->clist);
  958.  
  959.   colormap = gtk_widget_get_colormap (g_editor->clist);
  960.   gdk_color_parse ("black", &black);
  961.   gdk_color_alloc (colormap, &black);
  962.     
  963.   gtk_signal_connect (GTK_OBJECT (g_editor->clist), "button_press_event",
  964.                       GTK_SIGNAL_FUNC (gradient_editor_clist_button_press),
  965.                       NULL);
  966.  
  967.   gtk_signal_connect (GTK_OBJECT (g_editor->clist), "select_row",
  968.               GTK_SIGNAL_FUNC (ed_list_item_update),
  969.               NULL);
  970.  
  971.   /*  dnd stuff  */
  972.   gtk_drag_source_set (g_editor->clist,
  973.                GDK_BUTTON1_MASK | GDK_BUTTON2_MASK,
  974.                gradient_target_table, n_gradient_targets,
  975.                GDK_ACTION_COPY);
  976.   gimp_dnd_gradient_source_set (g_editor->clist, gradient_editor_drag_gradient,
  977.                 NULL);
  978.  
  979.   gtk_drag_dest_set (g_editor->clist,
  980.              GTK_DEST_DEFAULT_ALL,
  981.              gradient_target_table, n_gradient_targets,
  982.              GDK_ACTION_COPY);
  983.   gimp_dnd_gradient_dest_set (g_editor->clist, gradient_editor_drop_gradient,
  984.                   NULL);
  985.  
  986.   /* Frame & vbox for gradient functions */
  987.   frame = gtk_frame_new (_("Gradient Ops"));
  988.   gtk_box_pack_end (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
  989.  
  990.   gvbox = gtk_vbox_new (FALSE, 2);
  991.   gtk_container_set_border_width (GTK_CONTAINER (gvbox), 4);
  992.   gtk_container_add (GTK_CONTAINER (frame), gvbox);
  993.  
  994.   /* Buttons for gradient functions */
  995.   button = ed_create_button (_("New Gradient"),
  996.                  "dialogs/gradient_editor/new_gradient.html",
  997.                  GTK_SIGNAL_FUNC (ed_new_gradient_callback),
  998.                  NULL);
  999.   GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
  1000.   gtk_box_pack_start (GTK_BOX (gvbox), button, FALSE, FALSE, 0);
  1001.   gtk_widget_show (button);
  1002.  
  1003.   button = ed_create_button (_("Copy Gradient"),
  1004.                  "dialogs/gradient_editor/copy_gradient.html",
  1005.                  GTK_SIGNAL_FUNC (ed_copy_gradient_callback),
  1006.                  NULL);
  1007.   GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
  1008.   gtk_box_pack_start (GTK_BOX (gvbox), button, FALSE, FALSE, 0);
  1009.   gtk_widget_show (button);
  1010.  
  1011.   button = ed_create_button (_("Delete Gradient"),
  1012.                  "dialogs/gradient_editor/delete_gradient.html",
  1013.                  GTK_SIGNAL_FUNC (ed_delete_gradient_callback),
  1014.                  NULL);
  1015.   GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
  1016.   gtk_box_pack_start (GTK_BOX (gvbox), button, FALSE, FALSE, 0);
  1017.   gtk_widget_show (button);
  1018.  
  1019.   button = ed_create_button (_("Rename Gradient"),
  1020.                  "dialogs/gradient_editor/rename_gradient.html",
  1021.                  GTK_SIGNAL_FUNC (ed_rename_gradient_callback),
  1022.                  NULL);
  1023.   GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
  1024.   gtk_box_pack_start (GTK_BOX (gvbox), button, FALSE, FALSE, 0);
  1025.   gtk_widget_show (button);
  1026.  
  1027.   button = ed_create_button (_("Save as POV-Ray"),
  1028.                  "dialogs/gradient_editor/save_as_povray.html",
  1029.                  GTK_SIGNAL_FUNC (ed_save_pov_callback),
  1030.                  NULL);
  1031.   GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
  1032.   gtk_box_pack_start (GTK_BOX (gvbox), button, FALSE, FALSE, 0);
  1033.   gtk_widget_show (button);
  1034.  
  1035.   gtk_widget_show (gvbox);
  1036.   gtk_widget_show (frame);
  1037.  
  1038.   /*  Horizontal box for zoom controls, scrollbar and instant update toggle  */
  1039.   hbox = gtk_hbox_new (FALSE, 4);
  1040.   gtk_container_set_border_width (GTK_CONTAINER (hbox), 0);
  1041.   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
  1042.   gtk_widget_show (hbox);
  1043.  
  1044.   /*  Zoom all button */
  1045.   button = ed_create_button (_("Zoom all"), NULL,
  1046.                  GTK_SIGNAL_FUNC (ed_zoom_all_callback),
  1047.                  g_editor);
  1048.   GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
  1049.   gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
  1050.   gtk_widget_show (button);
  1051.  
  1052.   /*  + and - buttons  */
  1053.   gtk_widget_realize (g_editor->shell);
  1054.  
  1055.   button = gimp_pixmap_button_new (zoom_in_xpm, NULL);
  1056.   GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
  1057.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  1058.               GTK_SIGNAL_FUNC (ed_zoom_in_callback),
  1059.               g_editor);
  1060.   gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
  1061.   gtk_widget_show (button);
  1062.  
  1063.   button = gimp_pixmap_button_new (zoom_out_xpm, NULL);
  1064.   GTK_WIDGET_UNSET_FLAGS (button, GTK_RECEIVES_DEFAULT);
  1065.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  1066.               GTK_SIGNAL_FUNC (ed_zoom_out_callback),
  1067.               g_editor);
  1068.   gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
  1069.   gtk_widget_show (button);
  1070.  
  1071.   /*  Scrollbar  */
  1072.   g_editor->zoom_factor = 1;
  1073.  
  1074.   g_editor->scroll_data = gtk_adjustment_new (0.0, 0.0, 1.0,
  1075.                           1.0 * GRAD_SCROLLBAR_STEP_SIZE,
  1076.                           1.0 * GRAD_SCROLLBAR_PAGE_SIZE,
  1077.                           1.0);
  1078.  
  1079.   gtk_signal_connect (g_editor->scroll_data, "value_changed",
  1080.               GTK_SIGNAL_FUNC (ed_scrollbar_update),
  1081.               g_editor);
  1082.   gtk_signal_connect (g_editor->scroll_data, "changed",
  1083.               GTK_SIGNAL_FUNC (ed_scrollbar_update),
  1084.               g_editor);
  1085.  
  1086.   g_editor->scrollbar =
  1087.     gtk_hscrollbar_new (GTK_ADJUSTMENT (g_editor->scroll_data));
  1088.   gtk_range_set_update_policy (GTK_RANGE (g_editor->scrollbar),
  1089.                    GTK_UPDATE_CONTINUOUS);
  1090.   gtk_box_pack_start (GTK_BOX (hbox), g_editor->scrollbar, TRUE, TRUE, 0);
  1091.   gtk_widget_hide (g_editor->scrollbar);
  1092.  
  1093.   /* Instant update toggle */
  1094.   g_editor->instant_update = TRUE;
  1095.  
  1096.   button = gtk_check_button_new_with_label (_("Instant update"));
  1097.   gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
  1098.   gtk_signal_connect (GTK_OBJECT (button), "toggled",
  1099.               GTK_SIGNAL_FUNC (ed_instant_update_update),
  1100.               g_editor);
  1101.   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
  1102.   gtk_widget_show (button);
  1103.  
  1104.   /* Frame for gradient preview and gradient control */
  1105.   frame = gtk_frame_new (NULL);
  1106.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
  1107.   gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, FALSE, 0);
  1108.   gtk_widget_show (frame);
  1109.  
  1110.   gvbox = gtk_vbox_new (FALSE, 0);
  1111.   gtk_container_add (GTK_CONTAINER (frame), gvbox); 
  1112.   gtk_widget_show (gvbox);
  1113.  
  1114.   /* Gradient preview */
  1115.   g_editor->preview_rows[0]     = NULL;
  1116.   g_editor->preview_rows[1]     = NULL;
  1117.   g_editor->preview_last_x      = 0;
  1118.   g_editor->preview_button_down = FALSE;
  1119.  
  1120.   g_editor->preview = gtk_preview_new (GTK_PREVIEW_COLOR);
  1121.   gtk_preview_set_dither (GTK_PREVIEW (g_editor->preview), GDK_RGB_DITHER_MAX);
  1122.   gtk_preview_size (GTK_PREVIEW (g_editor->preview),
  1123.             GRAD_PREVIEW_WIDTH, GRAD_PREVIEW_HEIGHT);
  1124.  
  1125.   /*  Enable auto-resizing of the preview but ensure a minimal size  */
  1126.   gtk_widget_set_usize (g_editor->preview,
  1127.             GRAD_PREVIEW_WIDTH, GRAD_PREVIEW_HEIGHT);
  1128.   gtk_preview_set_expand (GTK_PREVIEW (g_editor->preview), TRUE);
  1129.  
  1130.   gtk_widget_set_events (g_editor->preview, GRAD_PREVIEW_EVENT_MASK);
  1131.   gtk_signal_connect (GTK_OBJECT (g_editor->preview), "event",
  1132.               GTK_SIGNAL_FUNC (preview_events),
  1133.               g_editor);
  1134.  
  1135.   gtk_drag_dest_set (g_editor->preview,
  1136.              GTK_DEST_DEFAULT_HIGHLIGHT |
  1137.              GTK_DEST_DEFAULT_MOTION |
  1138.              GTK_DEST_DEFAULT_DROP,
  1139.              gradient_target_table, n_gradient_targets,
  1140.              GDK_ACTION_COPY); 
  1141.   gimp_dnd_gradient_dest_set (g_editor->preview,
  1142.                   gradient_editor_drop_gradient,
  1143.                   NULL);
  1144.  
  1145.   gtk_box_pack_start (GTK_BOX (gvbox), g_editor->preview, TRUE, TRUE, 0);
  1146.   gtk_widget_show (g_editor->preview);
  1147.  
  1148.   /* Gradient control */
  1149.   g_editor->control_pixmap                  = NULL;
  1150.   g_editor->control_drag_segment            = NULL;
  1151.   g_editor->control_sel_l                   = NULL;
  1152.   g_editor->control_sel_r                   = NULL;
  1153.   g_editor->control_drag_mode               = GRAD_DRAG_NONE;
  1154.   g_editor->control_click_time              = 0;
  1155.   g_editor->control_compress                = FALSE;
  1156.   g_editor->control_last_x                  = 0;
  1157.   g_editor->control_last_gx                 = 0.0;
  1158.   g_editor->control_orig_pos                = 0.0;
  1159.   g_editor->control_main_popup              = NULL;
  1160.   g_editor->control_blending_label          = NULL;
  1161.   g_editor->control_coloring_label          = NULL;
  1162.   g_editor->control_split_m_label           = NULL;
  1163.   g_editor->control_split_u_label           = NULL;
  1164.   g_editor->control_delete_menu_item        = NULL;
  1165.   g_editor->control_delete_label            = NULL;
  1166.   g_editor->control_recenter_label          = NULL;
  1167.   g_editor->control_redistribute_label      = NULL;
  1168.   g_editor->control_flip_label              = NULL;
  1169.   g_editor->control_replicate_label         = NULL;
  1170.   g_editor->control_blend_colors_menu_item  = NULL;
  1171.   g_editor->control_blend_opacity_menu_item = NULL;
  1172.   g_editor->control_left_load_popup         = NULL;
  1173.   g_editor->control_left_save_popup         = NULL;
  1174.   g_editor->control_right_load_popup        = NULL;
  1175.   g_editor->control_right_save_popup        = NULL;
  1176.   g_editor->control_blending_popup          = NULL;
  1177.   g_editor->control_coloring_popup          = NULL;
  1178.   g_editor->control_sel_ops_popup           = NULL;
  1179.  
  1180.   g_editor->accel_group = NULL;
  1181.  
  1182.   for (i = 0;
  1183.        i < (sizeof (g_editor->control_blending_items) /
  1184.         sizeof (g_editor->control_blending_items[0]));
  1185.        i++)
  1186.     g_editor->control_blending_items[i] = NULL;
  1187.  
  1188.   for (i = 0;
  1189.        i < (sizeof (g_editor->control_coloring_items) /
  1190.         sizeof (g_editor->control_coloring_items[0]));
  1191.        i++)
  1192.     g_editor->control_coloring_items[i] = NULL;
  1193.  
  1194.   g_editor->control = gtk_drawing_area_new ();
  1195.   gtk_drawing_area_size (GTK_DRAWING_AREA (g_editor->control),
  1196.              GRAD_PREVIEW_WIDTH, GRAD_CONTROL_HEIGHT);
  1197.   gtk_widget_set_events (g_editor->control, GRAD_CONTROL_EVENT_MASK);
  1198.   gtk_signal_connect (GTK_OBJECT (g_editor->control), "event",
  1199.               (GdkEventFunc) control_events,
  1200.               g_editor);
  1201.   gtk_box_pack_start (GTK_BOX (gvbox), g_editor->control, TRUE, TRUE, 0);
  1202.   gtk_widget_show (g_editor->control);
  1203.  
  1204.   /* Hint bar and close button */
  1205.   g_editor->hint_label = gtk_label_new ("");
  1206.   gtk_misc_set_alignment (GTK_MISC (g_editor->hint_label), 0.0, 0.5);
  1207.   gtk_box_pack_start (GTK_BOX (vbox), g_editor->hint_label, FALSE, FALSE, 0);
  1208.   gtk_widget_show (g_editor->hint_label);
  1209.  
  1210.   /* Initialize other data */
  1211.   g_editor->left_color_preview  = NULL;
  1212.   g_editor->left_saved_segments = NULL;
  1213.   g_editor->left_saved_dirty    = FALSE;
  1214.  
  1215.   g_editor->right_color_preview  = NULL;
  1216.   g_editor->right_saved_segments = NULL;
  1217.   g_editor->right_saved_dirty    = FALSE;
  1218.  
  1219.   ed_initialize_saved_colors ();
  1220.   cpopup_create_main_menu ();
  1221.  
  1222.   if (gradients_list)
  1223.     {
  1224.       curr_gradient = dnd_gradient = (gradient_t *) gradients_list->data;
  1225.     }
  1226.   else
  1227.     {
  1228.       gint pos;
  1229.  
  1230.       curr_gradient = dnd_gradient = grad_create_default_gradient ();
  1231.       curr_gradient->name     = g_strdup (_("Default"));
  1232.       curr_gradient->filename =
  1233.     build_user_filename (curr_gradient->name, gradient_path);
  1234.       curr_gradient->dirty    = FALSE;
  1235.  
  1236.       pos = grad_insert_in_gradients_list (curr_gradient);
  1237.       gradient_select_insert_all (pos, curr_gradient);
  1238.       gimp_context_refresh_gradients ();
  1239.     }
  1240.  
  1241.   /* Show everything */
  1242.   g_editor->gc = gdk_gc_new (g_editor->shell->window);
  1243.   select_pos = gradient_clist_init (g_editor->shell, g_editor->gc,
  1244.                     g_editor->clist,
  1245.                     curr_gradient);
  1246.  
  1247.   gtk_widget_show (g_editor->shell);
  1248.  
  1249.   if (select_pos != -1)
  1250.     gtk_clist_moveto (GTK_CLIST (g_editor->clist), select_pos, 0, 0.0, 0.0);
  1251. }
  1252.  
  1253. void
  1254. gradient_editor_free (void)
  1255. {
  1256. }
  1257.  
  1258. gboolean
  1259. gradient_editor_set_gradient (gradient_t *gradient)
  1260. {
  1261.   gint n;
  1262.  
  1263.   n = gradient_list_get_gradient_index (gradients_list, gradient);
  1264.  
  1265.   if (n < 0)
  1266.     return FALSE;
  1267.  
  1268.   if (g_editor)
  1269.     {
  1270.       gtk_clist_select_row (GTK_CLIST (g_editor->clist), n, -1);
  1271.       gtk_clist_moveto (GTK_CLIST (g_editor->clist), n, 0, 0.5, 0.0);
  1272.     }
  1273.   else
  1274.     {
  1275.       curr_gradient = dnd_gradient = gradient;
  1276.     }
  1277.  
  1278.   return TRUE;
  1279. }
  1280.  
  1281. /***** Gradient editor functions *****/
  1282.  
  1283. static gint
  1284. gradient_editor_clist_button_press (GtkWidget      *widget,
  1285.                     GdkEventButton *bevent,
  1286.                     gpointer        data)
  1287. {
  1288.   if (bevent->button == 2)
  1289.     {
  1290.       GSList *list = NULL;
  1291.       gint row;
  1292.       gint column;
  1293.  
  1294.       gtk_clist_get_selection_info (GTK_CLIST (g_editor->clist),
  1295.                                     bevent->x, bevent->y,
  1296.                                     &row, &column);
  1297.  
  1298.       if (gradients_list)
  1299.     list = g_slist_nth (gradients_list, row);
  1300.  
  1301.       if (list)
  1302.     dnd_gradient = (gradient_t *) list->data;
  1303.       else
  1304.     dnd_gradient = NULL;
  1305.  
  1306.       return TRUE;
  1307.     }
  1308.  
  1309.   return FALSE;
  1310. }
  1311.  
  1312. static gradient_t *
  1313. gradient_editor_drag_gradient (GtkWidget  *widget,
  1314.                    gpointer    data)
  1315. {
  1316.   return dnd_gradient;
  1317. }
  1318.  
  1319. static void
  1320. gradient_editor_drop_gradient (GtkWidget  *widget,
  1321.                    gradient_t *gradient,
  1322.                    gpointer    data)
  1323. {
  1324.   gradient_editor_set_gradient (gradient);
  1325. }
  1326.  
  1327. /*****/
  1328.  
  1329. static void
  1330. ed_fetch_foreground (gdouble *fg_r,
  1331.              gdouble *fg_g,
  1332.              gdouble *fg_b,
  1333.              gdouble *fg_a)
  1334. {
  1335.   guchar r, g, b;
  1336.     
  1337.   gimp_context_get_foreground (gimp_context_get_user (), &r, &g, &b);
  1338.      
  1339.   *fg_r = (gdouble) r / 255.0;
  1340.   *fg_g = (gdouble) g / 255.0;
  1341.   *fg_b = (gdouble) b / 255.0;
  1342.   *fg_a = 1.0;                 /* opacity 100 % */
  1343. }
  1344.  
  1345. /*****/
  1346.  
  1347. static void
  1348. ed_update_editor (int flags)
  1349. {
  1350.   if (flags & GRAD_UPDATE_GRADIENT)
  1351.     {
  1352.       preview_update (TRUE);
  1353.       gradient_update ();
  1354.     }
  1355.  
  1356.   if (flags & GRAD_UPDATE_PREVIEW)
  1357.     preview_update (TRUE);
  1358.  
  1359.   if (flags & GRAD_UPDATE_CONTROL)
  1360.     control_update (FALSE);
  1361.  
  1362.   if (flags & GRAD_RESET_CONTROL)
  1363.     control_update (TRUE);
  1364. }
  1365.  
  1366. /*****/
  1367.  
  1368. static GtkWidget *
  1369. ed_create_button (gchar         *label,
  1370.           gchar         *help_data,
  1371.           GtkSignalFunc  signal_func,
  1372.           gpointer       data)
  1373. {
  1374.   GtkWidget *button;
  1375.  
  1376.   button = gtk_button_new_with_label (label);
  1377.   gtk_misc_set_padding (GTK_MISC (GTK_BIN (button)->child), 2, 0);
  1378.   gtk_widget_show (button); 
  1379.  
  1380.   if (signal_func != NULL)
  1381.     gtk_signal_connect (GTK_OBJECT (button), "clicked",
  1382.             signal_func,
  1383.             data);
  1384.  
  1385.   if (help_data)
  1386.     gimp_help_set_help_data (button, NULL, help_data);
  1387.  
  1388.   return button;
  1389. }
  1390.  
  1391. /*****/
  1392.  
  1393. static void
  1394. ed_set_hint (gchar *str)
  1395. {
  1396.   gtk_label_set_text (GTK_LABEL (g_editor->hint_label), str);
  1397. }
  1398.  
  1399. /*****/
  1400.  
  1401. static void
  1402. gradient_clist_fill_preview (gradient_t *gradient,
  1403.                  guchar     *buf,
  1404.                  gint        width,
  1405.                  gint        height,
  1406.                  gdouble     left,
  1407.                  gdouble     right)
  1408. {
  1409.   guchar  *p0, *p1;
  1410.   guchar  *even, *odd;
  1411.   gint     x, y;
  1412.   gdouble  dx, cur_x;
  1413.   gdouble  r, g, b, a;
  1414.   gdouble  c0, c1;
  1415.  
  1416.   dx    = (right - left) / (width - 1);
  1417.   cur_x = left;
  1418.   p0    = even = g_malloc (width * 3);
  1419.   p1    = odd  = g_malloc (width * 3);
  1420.  
  1421.   /* Create lines to fill the image */
  1422.  
  1423.   for (x = 0; x < width; x++)
  1424.     {
  1425.       gradient_get_color_at (gradient, cur_x, &r, &g, &b, &a);
  1426.  
  1427.       if ((x / GIMP_CHECK_SIZE_SM) & 1)
  1428.     {
  1429.       c0 = GIMP_CHECK_LIGHT;
  1430.       c1 = GIMP_CHECK_DARK;
  1431.     }
  1432.       else
  1433.     {
  1434.       c0 = GIMP_CHECK_DARK;
  1435.       c1 = GIMP_CHECK_LIGHT;
  1436.     }
  1437.  
  1438.       *p0++ = (c0 + (r - c0) * a) * 255.0;
  1439.       *p0++ = (c0 + (g - c0) * a) * 255.0;
  1440.       *p0++ = (c0 + (b - c0) * a) * 255.0;
  1441.  
  1442.       *p1++ = (c1 + (r - c1) * a) * 255.0;
  1443.       *p1++ = (c1 + (g - c1) * a) * 255.0;
  1444.       *p1++ = (c1 + (b - c1) * a) * 255.0;
  1445.  
  1446.       cur_x += dx;
  1447.     }
  1448.  
  1449.   for (y = 0; y < height; y++)
  1450.     {
  1451.       if ((y / GIMP_CHECK_SIZE_SM) & 1)
  1452.     {
  1453.       memcpy (buf + (width * y * 3), odd, width * 3); 
  1454.     }
  1455.       else
  1456.     {
  1457.       memcpy (buf + (width * y * 3), even, width * 3); 
  1458.     }
  1459.     }
  1460.  
  1461.   g_free (even);
  1462.   g_free (odd);
  1463. }
  1464.  
  1465. static void
  1466. gradient_clist_draw_small_preview (GdkGC      *gc,
  1467.                    GtkWidget  *clist,
  1468.                    gradient_t *gradient,
  1469.                    gint        pos)
  1470. {
  1471.   guchar rgb_buf[48 * 16 * 3];
  1472.  
  1473.   gradient_clist_fill_preview (gradient, rgb_buf, 48, 16, 0.0, 1.0);
  1474.  
  1475.   gdk_draw_rgb_image (gradient->pixmap, gc,
  1476.               0, 0,
  1477.               48, 16,
  1478.               GDK_RGB_DITHER_NORMAL,
  1479.               rgb_buf,
  1480.               48 * 3);
  1481.  
  1482.   gdk_gc_set_foreground (gc, &black);
  1483.   gdk_draw_rectangle (gradient->pixmap, gc, FALSE, 0, 0, 47, 15);
  1484.   gtk_clist_set_text (GTK_CLIST (clist), pos, 1, gradient->name);  
  1485. }
  1486.  
  1487. gint
  1488. gradient_clist_init (GtkWidget  *shell,
  1489.              GdkGC      *gc,
  1490.              GtkWidget  *clist,
  1491.              gradient_t *sel_gradient)
  1492. {
  1493.   GSList     *list;
  1494.   gradient_t *gradient;
  1495.   gint n;
  1496.   gint select_pos = -1;
  1497.  
  1498.   if (sel_gradient == NULL)
  1499.     sel_gradient = curr_gradient;
  1500.  
  1501.   if (sel_gradient == NULL)
  1502.     return 0;
  1503.  
  1504.   gtk_clist_freeze (GTK_CLIST (clist));
  1505.  
  1506.   for (list = gradients_list, n = 0; list; list = g_slist_next (list), n++)
  1507.     {
  1508.       gradient = (gradient_t *) list->data;
  1509.  
  1510.       if (gradient == sel_gradient)
  1511.     {
  1512.       gradient_clist_insert (shell, gc, clist, gradient, n, TRUE);
  1513.       select_pos = n;
  1514.     }
  1515.       else
  1516.     {
  1517.       gradient_clist_insert (shell, gc, clist, gradient, n, FALSE);
  1518.     }
  1519.     }
  1520.  
  1521.   gtk_clist_thaw (GTK_CLIST (clist));
  1522.  
  1523.   return select_pos;
  1524. }
  1525.  
  1526. void
  1527. gradient_clist_insert (GtkWidget  *shell,
  1528.                GdkGC      *gc,
  1529.                GtkWidget  *clist,
  1530.                gradient_t *gradient,
  1531.                gint        pos,
  1532.                gboolean    select)
  1533. {
  1534.   gchar *string[2];
  1535.  
  1536.   g_return_if_fail (gradient != NULL);
  1537.  
  1538.   string[0] = NULL;
  1539.   string[1] = gradient->name;
  1540.  
  1541.   pos = gtk_clist_insert (GTK_CLIST (clist), pos, string);
  1542.   gtk_clist_set_row_data (GTK_CLIST (clist), pos, gradient);
  1543.  
  1544.   if (gradient->pixmap == NULL)
  1545.     {
  1546.       gradient->pixmap =
  1547.     gdk_pixmap_new (shell->window, 48, 16,
  1548.             gtk_widget_get_visual (shell)->depth);
  1549.     }
  1550.  
  1551.   gradient_clist_draw_small_preview (gc, clist, gradient, pos);
  1552.  
  1553.   gtk_clist_set_pixmap (GTK_CLIST (clist), pos, 0, gradient->pixmap, NULL);
  1554.  
  1555.   if (select)
  1556.     {
  1557.       gtk_clist_select_row (GTK_CLIST (clist), pos, -1);
  1558.       gtk_clist_moveto (GTK_CLIST (clist), pos, 0, 0.5, 0.0);
  1559.     }
  1560. }
  1561.  
  1562. /*****/
  1563.  
  1564. static void
  1565. ed_list_item_update (GtkWidget      *widget, 
  1566.              gint            row,
  1567.              gint            column,
  1568.              GdkEventButton *event,
  1569.              gpointer        data)
  1570. {
  1571.   /* Update current gradient */
  1572.   curr_gradient = dnd_gradient = 
  1573.     (gradient_t *) gtk_clist_get_row_data (GTK_CLIST (widget), row); 
  1574.  
  1575.   ed_update_editor (GRAD_UPDATE_PREVIEW | GRAD_RESET_CONTROL);
  1576. }
  1577.  
  1578. /*****/
  1579.  
  1580. static void
  1581. ed_initialize_saved_colors (void)
  1582. {
  1583.   int i;
  1584.  
  1585.   for (i = 0; i < (GRAD_NUM_COLORS + 3); i++)
  1586.     {
  1587.       g_editor->left_load_color_boxes[i] = NULL;
  1588.       g_editor->left_load_labels[i]      = NULL;
  1589.  
  1590.       g_editor->right_load_color_boxes[i] = NULL;
  1591.       g_editor->right_load_labels[i]      = NULL;
  1592.     }
  1593.  
  1594.   for (i = 0; i < GRAD_NUM_COLORS; i++)
  1595.     {
  1596.       g_editor->left_save_color_boxes[i] = NULL;
  1597.       g_editor->left_save_labels[i]      = NULL;
  1598.  
  1599.       g_editor->right_save_color_boxes[i] = NULL;
  1600.       g_editor->right_save_labels[i]      = NULL;
  1601.     }
  1602.  
  1603.   g_editor->saved_colors[0].r = 0.0; /* Black */
  1604.   g_editor->saved_colors[0].g = 0.0;
  1605.   g_editor->saved_colors[0].b = 0.0;
  1606.   g_editor->saved_colors[0].a = 1.0;
  1607.  
  1608.   g_editor->saved_colors[1].r = 0.5; /* 50% Gray */
  1609.   g_editor->saved_colors[1].g = 0.5;
  1610.   g_editor->saved_colors[1].b = 0.5;
  1611.   g_editor->saved_colors[1].a = 1.0;
  1612.  
  1613.   g_editor->saved_colors[2].r = 1.0; /* White */
  1614.   g_editor->saved_colors[2].g = 1.0;
  1615.   g_editor->saved_colors[2].b = 1.0;
  1616.   g_editor->saved_colors[2].a = 1.0;
  1617.  
  1618.   g_editor->saved_colors[3].r = 0.0; /* Clear */
  1619.   g_editor->saved_colors[3].g = 0.0;
  1620.   g_editor->saved_colors[3].b = 0.0;
  1621.   g_editor->saved_colors[3].a = 0.0;
  1622.  
  1623.   g_editor->saved_colors[4].r = 1.0; /* Red */
  1624.   g_editor->saved_colors[4].g = 0.0;
  1625.   g_editor->saved_colors[4].b = 0.0;
  1626.   g_editor->saved_colors[4].a = 1.0;
  1627.  
  1628.   g_editor->saved_colors[5].r = 1.0; /* Yellow */
  1629.   g_editor->saved_colors[5].g = 1.0;
  1630.   g_editor->saved_colors[5].b = 0.0;
  1631.   g_editor->saved_colors[5].a = 1.0;
  1632.  
  1633.   g_editor->saved_colors[6].r = 0.0; /* Green */
  1634.   g_editor->saved_colors[6].g = 1.0;
  1635.   g_editor->saved_colors[6].b = 0.0;
  1636.   g_editor->saved_colors[6].a = 1.0;
  1637.  
  1638.   g_editor->saved_colors[7].r = 0.0; /* Cyan */
  1639.   g_editor->saved_colors[7].g = 1.0;
  1640.   g_editor->saved_colors[7].b = 1.0;
  1641.   g_editor->saved_colors[7].a = 1.0;
  1642.  
  1643.   g_editor->saved_colors[8].r = 0.0; /* Blue */
  1644.   g_editor->saved_colors[8].g = 0.0;
  1645.   g_editor->saved_colors[8].b = 1.0;
  1646.   g_editor->saved_colors[8].a = 1.0;
  1647.  
  1648.   g_editor->saved_colors[9].r = 1.0; /* Magenta */
  1649.   g_editor->saved_colors[9].g = 0.0;
  1650.   g_editor->saved_colors[9].b = 1.0;
  1651.   g_editor->saved_colors[9].a = 1.0;
  1652. }
  1653.  
  1654. /***** Main gradient editor dialog callbacks *****/
  1655.  
  1656. /***** the "new gradient" dialog functions *****/
  1657.  
  1658. static void
  1659. ed_new_gradient_callback (GtkWidget *widget,
  1660.               gpointer   data)
  1661. {
  1662.   GtkWidget *qbox;
  1663.  
  1664.   qbox = gimp_query_string_box (_("New gradient"),
  1665.                 gimp_standard_help_func,
  1666.                 "dialogs/gradient_editor/new_gradient.html",
  1667.                 _("Enter a name for the new gradient"),
  1668.                 _("untitled"),
  1669.                 NULL, NULL,
  1670.                 ed_do_new_gradient_callback, NULL);
  1671.   gtk_widget_show (qbox);
  1672. }
  1673.  
  1674. static void
  1675. ed_do_new_gradient_callback (GtkWidget *widget,
  1676.                  gchar     *gradient_name,
  1677.                  gpointer   data)
  1678. {
  1679.   gradient_t *grad;
  1680.   gint        pos;
  1681.  
  1682.   if (!gradient_name)
  1683.     {
  1684.       g_warning ("received NULL in call_data");
  1685.       return;
  1686.     }
  1687.  
  1688.   grad = grad_create_default_gradient ();
  1689.  
  1690.   grad->name     = gradient_name; /* We don't need to copy since 
  1691.                      this memory is ours */
  1692.   grad->dirty    = TRUE;
  1693.   grad->filename = build_user_filename (grad->name, gradient_path);
  1694.  
  1695.   /* Put new gradient in list */
  1696.  
  1697.   pos = grad_insert_in_gradients_list (grad);
  1698.   gtk_clist_freeze (GTK_CLIST (g_editor->clist));
  1699.   gradient_clist_insert (g_editor->shell, g_editor->gc, g_editor->clist,
  1700.              grad, pos, TRUE);
  1701.   gtk_clist_thaw (GTK_CLIST (g_editor->clist));
  1702.   gtk_clist_moveto (GTK_CLIST (g_editor->clist), pos, 0, 0.5, 0.0);
  1703.  
  1704.   curr_gradient = dnd_gradient = grad;
  1705.  
  1706.   ed_update_editor (GRAD_UPDATE_PREVIEW | GRAD_RESET_CONTROL);
  1707.  
  1708.   gradient_select_insert_all (pos, grad);
  1709. }
  1710.  
  1711. /***** The "copy gradient" dialog functions *****/
  1712.  
  1713. static void
  1714. ed_copy_gradient_callback (GtkWidget *widget,
  1715.                gpointer   data)
  1716. {
  1717.   GtkWidget *qbox;
  1718.   gchar     *name;
  1719.  
  1720.   if (curr_gradient == NULL) 
  1721.     return;
  1722.  
  1723.   name = g_strdup_printf (_("%s copy"), curr_gradient->name);
  1724.  
  1725.   qbox = gimp_query_string_box (_("Copy gradient"),
  1726.                 gimp_standard_help_func,
  1727.                 "dialogs/gradient_editor/copy_gradient.html",
  1728.                 _("Enter a name for the copied gradient"),
  1729.                 name,
  1730.                 NULL, NULL,
  1731.                 ed_do_copy_gradient_callback, NULL);
  1732.   gtk_widget_show (qbox);
  1733.  
  1734.   g_free (name);
  1735. }
  1736.  
  1737. static void
  1738. ed_do_copy_gradient_callback (GtkWidget *widget,
  1739.                   gchar     *gradient_name,
  1740.                   gpointer   data)
  1741. {
  1742.   gradient_t     *grad;
  1743.   gint            pos;
  1744.   grad_segment_t *head, *prev, *cur, *orig;
  1745.  
  1746.   if (!gradient_name)
  1747.     {
  1748.       g_warning ("received NULL in call_data");
  1749.       return;
  1750.     }
  1751.  
  1752.   /* Copy current gradient */
  1753.   grad = grad_new_gradient ();
  1754.   if (grad == NULL)
  1755.     return;
  1756.  
  1757.   grad->name     = gradient_name; /* We don't need to copy since 
  1758.                      this memory is ours */
  1759.   grad->dirty    = TRUE;
  1760.   grad->filename = build_user_filename (grad->name, gradient_path);
  1761.  
  1762.   prev = NULL;
  1763.   orig = curr_gradient->segments;
  1764.   head = NULL;
  1765.  
  1766.   while (orig)
  1767.     {
  1768.       cur = seg_new_segment ();
  1769.  
  1770.       *cur = *orig;  /* Copy everything */
  1771.  
  1772.       cur->prev = prev;
  1773.       cur->next = NULL;
  1774.  
  1775.       if (prev)
  1776.     prev->next = cur;
  1777.       else
  1778.     head = cur;  /* Remember head */
  1779.  
  1780.       prev = cur;
  1781.       orig = orig->next;
  1782.     }
  1783.  
  1784.   grad->segments = head;
  1785.  
  1786.   /* Put new gradient in list */
  1787.   pos = grad_insert_in_gradients_list (grad);
  1788.   gtk_clist_freeze (GTK_CLIST (g_editor->clist));
  1789.   gradient_clist_insert (g_editor->shell, g_editor->gc, g_editor->clist,
  1790.              grad, pos, TRUE);
  1791.   gtk_clist_thaw (GTK_CLIST (g_editor->clist));
  1792.  
  1793.   curr_gradient = dnd_gradient = grad;
  1794.  
  1795.   ed_update_editor (GRAD_UPDATE_PREVIEW | GRAD_RESET_CONTROL);
  1796.  
  1797.   gradient_select_insert_all (pos, grad);
  1798. }
  1799.  
  1800. /***** The "rename gradient" dialog functions *****/
  1801.  
  1802. static void
  1803. ed_rename_gradient_callback (GtkWidget *widget,
  1804.                  gpointer   data)
  1805. {
  1806.   GtkWidget *qbox;
  1807.  
  1808.   if (curr_gradient == NULL)
  1809.     return;
  1810.  
  1811.   qbox = gimp_query_string_box (_("Rename gradient"),
  1812.                 gimp_standard_help_func,
  1813.                 "dialogs/gradient_editor/rename_gradient.html",
  1814.                 _("Enter a new name for the gradient"),
  1815.                 curr_gradient->name,
  1816.                 NULL, NULL,
  1817.                 ed_do_rename_gradient_callback,
  1818.                 curr_gradient);
  1819.   gtk_widget_show (qbox);
  1820. }
  1821.  
  1822. static void
  1823. ed_do_rename_gradient_callback (GtkWidget *widget,
  1824.                 gchar     *gradient_name,
  1825.                 gpointer   data)
  1826. {
  1827.   gradient_t *grad = (gradient_t *) data;
  1828.   gint        row;
  1829.  
  1830.   g_return_if_fail (grad != NULL);
  1831.  
  1832.   if (!gradient_name)
  1833.     {
  1834.       g_warning ("received NULL in call_data");
  1835.       return;
  1836.     }
  1837.  
  1838.   g_free (grad->name);
  1839.   grad->name  = gradient_name; /* We don't need to copy since 
  1840.                   this memory is ours */
  1841.   grad->dirty = TRUE;
  1842.  
  1843.   /* Delete file and free gradient */
  1844.   unlink (grad->filename);
  1845.  
  1846.   g_free (grad->filename);
  1847.   grad->filename = build_user_filename (grad->name, gradient_path);
  1848.  
  1849.   row = gtk_clist_find_row_from_data (GTK_CLIST (g_editor->clist), grad);
  1850.   if (row > -1)
  1851.     gtk_clist_set_text (GTK_CLIST (g_editor->clist), row, 1, grad->name);
  1852.  
  1853.   gradient_select_rename_all (grad);
  1854.  
  1855.   ed_update_editor (GRAD_UPDATE_PREVIEW | GRAD_RESET_CONTROL);
  1856.     
  1857.   gimp_context_update_gradients (grad);
  1858. }
  1859.  
  1860. /***** The "delete gradient" dialog functions *****/
  1861.  
  1862. static void
  1863. ed_delete_gradient_callback (GtkWidget *widget,
  1864.                  gpointer   data)
  1865. {
  1866.   GtkWidget *dialog;
  1867.   gchar     *str;
  1868.  
  1869.   if (num_gradients <= 1 || curr_gradient == NULL)
  1870.     return;
  1871.  
  1872.   gtk_widget_set_sensitive (g_editor->shell, FALSE);
  1873.  
  1874.   str = g_strdup_printf (_("Are you sure you want to delete\n"
  1875.                "\"%s\" from the list and from disk?"),
  1876.              curr_gradient->name);
  1877.  
  1878.   dialog =
  1879.     gimp_query_boolean_box (_("Delete Gradient"),
  1880.                 gimp_standard_help_func,
  1881.                 "dialogs/gradient_editor/delete_gradient.html",
  1882.                 FALSE,
  1883.                 str,
  1884.                 _("Delete"), _("Cancel"),
  1885.                 NULL, NULL,
  1886.                 ed_do_delete_gradient_callback,
  1887.                 NULL);
  1888.  
  1889.   g_free (str);
  1890.  
  1891.   gtk_widget_show (dialog);
  1892. }
  1893.  
  1894. static void
  1895. ed_do_delete_gradient_callback (GtkWidget *widget,
  1896.                 gboolean   delete,
  1897.                 gpointer   data)
  1898. {
  1899.   gradient_t *delete_gradient;
  1900.   gint        row;
  1901.  
  1902.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  1903.  
  1904.   if (! delete || curr_gradient == NULL)
  1905.     return;
  1906.   
  1907.   delete_gradient = curr_gradient;
  1908.   curr_gradient   = NULL;
  1909.  
  1910.  /* Delete gradient from clists */
  1911.   gradient_select_delete_all (delete_gradient);
  1912.  
  1913.   row = gtk_clist_find_row_from_data (GTK_CLIST (g_editor->clist), 
  1914.                       delete_gradient);
  1915.   if (row > -1)
  1916.     gtk_clist_remove (GTK_CLIST (g_editor->clist), row);
  1917.  
  1918.   /* Delete gradient from gradients list */
  1919.   gradients_list = g_slist_remove (gradients_list, delete_gradient);
  1920.   num_gradients--;
  1921.  
  1922.   /* Delete file and free gradient*/
  1923.   unlink (delete_gradient->filename);
  1924.   grad_free_gradient (delete_gradient);
  1925.  
  1926.   gimp_context_refresh_gradients ();
  1927. }
  1928.  
  1929. /***** The "save as pov" dialog functions *****/
  1930.  
  1931. static void
  1932. ed_save_pov_callback (GtkWidget *widget,
  1933.               gpointer   data)
  1934. {
  1935.   GtkWidget *window;
  1936.  
  1937.   if (curr_gradient == NULL)
  1938.     return;
  1939.  
  1940.   window = gtk_file_selection_new (_("Save as POV-Ray"));
  1941.   gtk_window_set_wmclass (GTK_WINDOW (window), "save_gradient", "Gimp");
  1942.   gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
  1943.  
  1944.   gtk_container_set_border_width (GTK_CONTAINER (window), 2);
  1945.   gtk_container_set_border_width (GTK_CONTAINER (GTK_FILE_SELECTION (window)->button_area), 2);
  1946.  
  1947.   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (window)->ok_button),
  1948.               "clicked",
  1949.               GTK_SIGNAL_FUNC (ed_do_save_pov_callback),
  1950.               window);
  1951.  
  1952.   gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (window)->cancel_button),
  1953.               "clicked",
  1954.               GTK_SIGNAL_FUNC (ed_cancel_save_pov_callback),
  1955.               window);
  1956.  
  1957.   gtk_signal_connect (GTK_OBJECT (window), "delete_event",
  1958.               GTK_SIGNAL_FUNC (ed_delete_save_pov_callback),
  1959.               window);
  1960.  
  1961.   /*  Connect the "F1" help key  */
  1962.   gimp_help_connect_help_accel (window, gimp_standard_help_func,
  1963.                 "dialogs/gradient_editor/save_as_povray.html");
  1964.  
  1965.   gtk_widget_show (window);
  1966.   gtk_widget_set_sensitive (g_editor->shell, FALSE);
  1967. }
  1968.  
  1969. static void
  1970. ed_do_save_pov_callback (GtkWidget *widget,
  1971.              gpointer   data)
  1972. {
  1973.   gchar          *filename;
  1974.   FILE           *file;
  1975.   grad_segment_t *seg;
  1976.  
  1977.   if (curr_gradient == NULL)
  1978.     return;
  1979.  
  1980.   filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (data));
  1981.  
  1982.   file = fopen (filename, "wb");
  1983.  
  1984.   if (!file)
  1985.     {
  1986.       g_message ("Could not open \"%s\"", filename);
  1987.     }
  1988.   else
  1989.     {
  1990.       fprintf (file, "/* color_map file created by the GIMP */\n");
  1991.       fprintf (file, "/* http://www.gimp.org/               */\n");
  1992.  
  1993.       fprintf (file, "color_map {\n");
  1994.  
  1995.       for (seg = curr_gradient->segments; seg; seg = seg->next)
  1996.     {
  1997.       /* Left */
  1998.       fprintf (file, "\t[%f color rgbt <%f, %f, %f, %f>]\n",
  1999.            seg->left,
  2000.            seg->r0, seg->g0, seg->b0, 1.0 - seg->a0);
  2001.  
  2002.       /* Middle */
  2003.       fprintf (file, "\t[%f color rgbt <%f, %f, %f, %f>]\n",
  2004.            seg->middle,
  2005.            (seg->r0 + seg->r1) / 2.0,
  2006.            (seg->g0 + seg->g1) / 2.0,
  2007.            (seg->b0 + seg->b1) / 2.0,
  2008.            1.0 - (seg->a0 + seg->a1) / 2.0);
  2009.  
  2010.       /* Right */
  2011.       fprintf (file, "\t[%f color rgbt <%f, %f, %f, %f>]\n",
  2012.            seg->right,
  2013.            seg->r1, seg->g1, seg->b1, 1.0 - seg->a1);
  2014.     }
  2015.  
  2016.       fprintf (file, "} /* color_map */\n");
  2017.       fclose (file);
  2018.     }
  2019.  
  2020.   gtk_widget_destroy (GTK_WIDGET (data));
  2021.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  2022. }
  2023.  
  2024. static void
  2025. ed_cancel_save_pov_callback (GtkWidget *widget,
  2026.                  gpointer   data)
  2027. {
  2028.   gtk_widget_destroy (GTK_WIDGET (data));
  2029.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  2030. }
  2031.  
  2032. static gint
  2033. ed_delete_save_pov_callback (GtkWidget *widget,
  2034.                  GdkEvent  *event,
  2035.                  gpointer   data)
  2036. {
  2037.   ed_cancel_save_pov_callback (widget, data);
  2038.  
  2039.   return TRUE;
  2040. }
  2041.  
  2042. /***** The main dialog action area button callbacks *****/
  2043.  
  2044. static void
  2045. ed_refresh_grads_callback (GtkWidget *widget,
  2046.                gpointer   data)
  2047. {
  2048.   gint select_pos;
  2049.  
  2050.   gtk_clist_freeze (GTK_CLIST (g_editor->clist));
  2051.   gtk_clist_clear (GTK_CLIST (g_editor->clist));
  2052.   gtk_clist_thaw (GTK_CLIST (g_editor->clist));
  2053.     
  2054.   gradient_select_free_all ();
  2055.  
  2056.   gradients_init (FALSE);
  2057.  
  2058.   if (gradients_list)
  2059.     {
  2060.       curr_gradient = dnd_gradient = (gradient_t *) gradients_list->data;
  2061.     }
  2062.   else
  2063.     {
  2064.       curr_gradient = dnd_gradient = grad_create_default_gradient ();
  2065.       curr_gradient->name     = g_strdup (_("Default"));
  2066.       curr_gradient->filename =
  2067.         build_user_filename (curr_gradient->name, gradient_path);
  2068.       curr_gradient->dirty    = FALSE;
  2069.  
  2070.       grad_insert_in_gradients_list (curr_gradient);
  2071.       gimp_context_refresh_gradients ();
  2072.     }
  2073.  
  2074.   select_pos = gradient_clist_init (g_editor->shell, g_editor->gc,
  2075.                     g_editor->clist,
  2076.                     curr_gradient);
  2077.  
  2078.   ed_update_editor (GRAD_UPDATE_PREVIEW | GRAD_RESET_CONTROL); 
  2079.  
  2080.   if (select_pos != -1)
  2081.     gtk_clist_moveto (GTK_CLIST (g_editor->clist), select_pos, 0, 0.5, 0.0);
  2082.  
  2083.   gradient_select_refill_all ();
  2084. }
  2085.  
  2086. static void
  2087. ed_close_callback (GtkWidget *widget,
  2088.            gpointer   data)
  2089. {
  2090.   if (GTK_WIDGET_VISIBLE (g_editor->shell))
  2091.     gtk_widget_hide (g_editor->shell);
  2092. }
  2093.  
  2094. /***** Zoom, scrollbar & instant update callbacks *****/
  2095.  
  2096. static void
  2097. ed_scrollbar_update (GtkAdjustment *adjustment,
  2098.              gpointer       data)
  2099. {
  2100.   gchar *str;
  2101.  
  2102.   str = g_strdup_printf (_("Zoom factor: %d:1    Displaying [%0.6f, %0.6f]"),
  2103.              g_editor->zoom_factor, adjustment->value,
  2104.              adjustment->value + adjustment->page_size);
  2105.  
  2106.   ed_set_hint (str);
  2107.   g_free (str);
  2108.  
  2109.   ed_update_editor (GRAD_UPDATE_PREVIEW | GRAD_UPDATE_CONTROL);
  2110. }
  2111.  
  2112. static void
  2113. ed_zoom_all_callback (GtkWidget *widget,
  2114.               gpointer   data)
  2115. {
  2116.   GtkAdjustment *adjustment;
  2117.  
  2118.   adjustment = GTK_ADJUSTMENT (g_editor->scroll_data);
  2119.  
  2120.   g_editor->zoom_factor = 1;
  2121.  
  2122.   gtk_widget_hide (g_editor->scrollbar);
  2123.  
  2124.   adjustment->value            = 0.0;
  2125.   adjustment->page_size        = 1.0;
  2126.   adjustment->step_increment = 1.0 * GRAD_SCROLLBAR_STEP_SIZE;
  2127.   adjustment->page_increment = 1.0 * GRAD_SCROLLBAR_PAGE_SIZE;
  2128.  
  2129.   gtk_signal_emit_by_name (g_editor->scroll_data, "changed");
  2130. }
  2131.  
  2132. static void
  2133. ed_zoom_out_callback (GtkWidget *widget,
  2134.               gpointer   data)
  2135. {
  2136.   GtkAdjustment *adjustment;
  2137.   gdouble        old_value;
  2138.   gdouble        value;
  2139.   gdouble        old_page_size;
  2140.   gdouble        page_size;
  2141.  
  2142.   if (g_editor->zoom_factor <= 1)
  2143.     return;
  2144.  
  2145.   adjustment = GTK_ADJUSTMENT (g_editor->scroll_data);
  2146.  
  2147.   old_value     = adjustment->value;
  2148.   old_page_size = adjustment->page_size;
  2149.  
  2150.   g_editor->zoom_factor--;
  2151.  
  2152.   if (g_editor->zoom_factor==1)
  2153.     gtk_widget_hide (g_editor->scrollbar);
  2154.   else
  2155.     gtk_widget_show (g_editor->scrollbar);
  2156.  
  2157.   page_size = 1.0 / g_editor->zoom_factor;
  2158.   value     = old_value - (page_size - old_page_size) / 2.0;
  2159.  
  2160.   if (value < 0.0)
  2161.     value = 0.0;
  2162.   else if ((value + page_size) > 1.0)
  2163.     value = 1.0 - page_size;
  2164.  
  2165.   adjustment->value          = value;
  2166.   adjustment->page_size      = page_size;
  2167.   adjustment->step_increment = page_size * GRAD_SCROLLBAR_STEP_SIZE;
  2168.   adjustment->page_increment = page_size * GRAD_SCROLLBAR_PAGE_SIZE;
  2169.  
  2170.   gtk_signal_emit_by_name (g_editor->scroll_data, "changed");
  2171. }
  2172.  
  2173. static void
  2174. ed_zoom_in_callback (GtkWidget *widget,
  2175.              gpointer   data)
  2176. {
  2177.   GtkAdjustment *adjustment;
  2178.   gdouble        old_value;
  2179.   gdouble        old_page_size;
  2180.   gdouble        page_size;
  2181.  
  2182.   adjustment = GTK_ADJUSTMENT (g_editor->scroll_data);
  2183.  
  2184.   old_value     = adjustment->value;
  2185.   old_page_size = adjustment->page_size;
  2186.  
  2187.   g_editor->zoom_factor++;
  2188.  
  2189.   page_size = 1.0 / g_editor->zoom_factor;
  2190.  
  2191.   adjustment->value             = old_value + (old_page_size - page_size) / 2.0;
  2192.   adjustment->page_size      = page_size;
  2193.   adjustment->step_increment = page_size * GRAD_SCROLLBAR_STEP_SIZE;
  2194.   adjustment->page_increment = page_size * GRAD_SCROLLBAR_PAGE_SIZE;
  2195.  
  2196.   gtk_signal_emit_by_name (g_editor->scroll_data, "changed");
  2197.   gtk_widget_show (g_editor->scrollbar);
  2198. }
  2199.  
  2200. static void
  2201. ed_instant_update_update (GtkWidget *widget,
  2202.               gpointer   data)
  2203. {
  2204.   if (GTK_TOGGLE_BUTTON (widget)->active)
  2205.     {
  2206.       g_editor->instant_update = TRUE;
  2207.       gtk_range_set_update_policy (GTK_RANGE (g_editor->scrollbar),
  2208.                    GTK_UPDATE_CONTINUOUS);
  2209.     }
  2210.   else
  2211.     {
  2212.       g_editor->instant_update = FALSE;
  2213.       gtk_range_set_update_policy (GTK_RANGE (g_editor->scrollbar),
  2214.                    GTK_UPDATE_DELAYED);
  2215.     }
  2216. }
  2217.  
  2218. /***** Gradient preview functions *****/
  2219.  
  2220. static gint
  2221. preview_events (GtkWidget *widget,
  2222.          GdkEvent  *event,
  2223.          gpointer   data)
  2224. {
  2225.   gint            x, y;
  2226.   GdkEventButton *bevent;
  2227.   GdkEventMotion *mevent;
  2228.  
  2229.   /* ignore events when no gradient is present */
  2230.   if (curr_gradient == NULL) 
  2231.     return FALSE;
  2232.  
  2233.   switch (event->type)
  2234.     {
  2235.     case GDK_EXPOSE:
  2236.       preview_update (FALSE);
  2237.       break;
  2238.  
  2239.     case GDK_LEAVE_NOTIFY:
  2240.       ed_set_hint ("");
  2241.       break;
  2242.  
  2243.     case GDK_MOTION_NOTIFY:
  2244.       gtk_widget_get_pointer (g_editor->preview, &x, &y);
  2245.  
  2246.       mevent = (GdkEventMotion *) event;
  2247.  
  2248.       if (x != g_editor->preview_last_x)
  2249.     {
  2250.       g_editor->preview_last_x = x;
  2251.  
  2252.       if (g_editor->preview_button_down)
  2253.         {
  2254.           if (mevent->state & GDK_CONTROL_MASK)
  2255.         preview_set_background (x);
  2256.           else
  2257.         preview_set_foreground (x);
  2258.         }
  2259.       else
  2260.         {
  2261.           preview_set_hint (x);
  2262.         }
  2263.     }
  2264.       break;
  2265.  
  2266.     case GDK_BUTTON_PRESS:
  2267.       gtk_widget_get_pointer (g_editor->preview, &x, &y);
  2268.  
  2269.       bevent = (GdkEventButton *) event;
  2270.  
  2271.       switch (bevent->button)
  2272.     {
  2273.     case 1:
  2274.       g_editor->preview_last_x = x;
  2275.       g_editor->preview_button_down = TRUE;
  2276.       if (bevent->state & GDK_CONTROL_MASK)
  2277.         preview_set_background (x);
  2278.       else
  2279.         preview_set_foreground (x);
  2280.       break;
  2281.  
  2282.     case 3:
  2283.       cpopup_do_popup ();
  2284.       break;
  2285.  
  2286.       /*  wheelmouse support  */
  2287.     case 4:
  2288.       {
  2289.         GtkAdjustment *adj = GTK_ADJUSTMENT (g_editor->scroll_data);
  2290.         gfloat new_value = adj->value - adj->page_increment / 2;
  2291.         new_value =
  2292.           CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
  2293.         gtk_adjustment_set_value (adj, new_value);
  2294.       }
  2295.       break;
  2296.  
  2297.     case 5:
  2298.       {
  2299.         GtkAdjustment *adj = GTK_ADJUSTMENT (g_editor->scroll_data);
  2300.         gfloat new_value = adj->value + adj->page_increment / 2;
  2301.         new_value =
  2302.           CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
  2303.         gtk_adjustment_set_value (adj, new_value);
  2304.       }
  2305.       break;
  2306.  
  2307.     default:
  2308.       break;
  2309.     }
  2310.  
  2311.       break;
  2312.  
  2313.     case GDK_BUTTON_RELEASE:
  2314.       if (g_editor->preview_button_down)
  2315.     {
  2316.       gtk_widget_get_pointer (g_editor->preview, &x, &y);
  2317.  
  2318.       bevent = (GdkEventButton *) event;
  2319.  
  2320.       g_editor->preview_last_x = x;
  2321.       g_editor->preview_button_down = FALSE;
  2322.       if (bevent->state & GDK_CONTROL_MASK)
  2323.         preview_set_background (x);
  2324.       else
  2325.         preview_set_foreground (x);
  2326.       break;
  2327.     }
  2328.  
  2329.       break;
  2330.  
  2331.     default:
  2332.       break;
  2333.     }
  2334.  
  2335.   return FALSE;
  2336. }
  2337.  
  2338. /*****/
  2339.  
  2340. static void
  2341. preview_set_hint (gint x)
  2342. {
  2343.   gdouble  xpos;
  2344.   gdouble  r, g, b, a;
  2345.   gdouble  h, s, v;
  2346.   gchar   *str;
  2347.  
  2348.   xpos = control_calc_g_pos (x);
  2349.  
  2350.   gradient_get_color_at (curr_gradient, xpos, &r, &g, &b, &a);
  2351.  
  2352.   h = r;
  2353.   s = g;
  2354.   v = b;
  2355.  
  2356.   gimp_rgb_to_hsv_double (&h, &s, &v);
  2357.  
  2358.   str = g_strdup_printf (_("Position: %0.6f    "
  2359.                "RGB (%0.3f, %0.3f, %0.3f)    "
  2360.                "HSV (%0.3f, %0.3f, %0.3f)    "
  2361.                "Opacity: %0.3f"),
  2362.              xpos, r, g, b, h * 360.0, s, v, a);
  2363.  
  2364.   ed_set_hint (str);
  2365.   g_free (str);
  2366. }
  2367.  
  2368. /*****/
  2369.  
  2370. static void
  2371. preview_set_foreground (gint x)
  2372. {
  2373.   gdouble  xpos;
  2374.   gdouble  r, g, b, a;
  2375.   gchar   *str;
  2376.  
  2377.   xpos = control_calc_g_pos (x);
  2378.   gradient_get_color_at (curr_gradient, xpos, &r, &g, &b, &a);
  2379.  
  2380.   gimp_context_set_foreground (gimp_context_get_user (),
  2381.                    r * 255.0, g * 255.0, b * 255.0);
  2382.  
  2383.   str = g_strdup_printf (_("Foreground color set to RGB (%d, %d, %d) <-> "
  2384.                "(%0.3f, %0.3f, %0.3f)"),
  2385.              (gint) (r * 255.0),
  2386.              (gint) (g * 255.0),
  2387.              (gint) (b * 255.0),
  2388.              r, g, b);
  2389.  
  2390.   ed_set_hint (str);
  2391.   g_free (str);
  2392. }
  2393.  
  2394. static void
  2395. preview_set_background (gint x)
  2396. {
  2397.   gdouble xpos;
  2398.   gdouble r, g, b, a;
  2399.   gchar   *str;
  2400.  
  2401.   xpos = control_calc_g_pos (x);
  2402.   gradient_get_color_at (curr_gradient, xpos, &r, &g, &b, &a);
  2403.  
  2404.   gimp_context_set_background (gimp_context_get_user (),
  2405.                    r * 255.0, g * 255.0, b * 255.0);
  2406.  
  2407.   str = g_strdup_printf (_("Background color to RGB (%d, %d, %d) <-> "
  2408.                "(%0.3f, %0.3f, %0.3f)"),
  2409.              (gint) (r * 255.0),
  2410.              (gint) (g * 255.0),
  2411.              (gint) (b * 255.0),
  2412.              r, g, b);
  2413.  
  2414.   ed_set_hint (str);
  2415.   g_free (str);
  2416. }
  2417.  
  2418. /*****/
  2419.  
  2420. static void
  2421. gradient_update (void)
  2422. {
  2423.   gint row;
  2424.  
  2425.   row = gtk_clist_find_row_from_data (GTK_CLIST (g_editor->clist), 
  2426.                       curr_gradient);  
  2427.   if (row < 0)
  2428.     return;
  2429.  
  2430.   gradient_clist_draw_small_preview (g_editor->gc, g_editor->clist,
  2431.                      curr_gradient, row);
  2432.  
  2433.   /*  Update all selectors that are on screen  */
  2434.   gradient_select_update_all (curr_gradient);
  2435.  
  2436.   /*  Update all contexts  */
  2437.   gimp_context_update_gradients (curr_gradient);
  2438. }
  2439.  
  2440. static void
  2441. preview_update (gboolean recalculate)
  2442. {
  2443.   glong          rowsiz;
  2444.   GtkAdjustment *adjustment;
  2445.   guint16        width;
  2446.   guint16        height;
  2447.  
  2448.   static guint16  last_width  = 0;
  2449.   static guint16  last_height = 0;
  2450.  
  2451.   /* We only update if we can draw to the widget and a gradient is present */
  2452.   if (curr_gradient == NULL) 
  2453.     return;
  2454.  
  2455.   if (! GTK_WIDGET_DRAWABLE (g_editor->preview))
  2456.     return;
  2457.  
  2458.   /*  See whether we have to re-create the preview widget
  2459.    *  (note that the preview automatically follows the size of it's container)
  2460.    */
  2461.   width  = g_editor->preview->allocation.width;
  2462.   height = g_editor->preview->allocation.height;
  2463.  
  2464.   if (! g_editor->preview_rows[0] ||
  2465.       ! g_editor->preview_rows[1] ||
  2466.       (width  != last_width)      ||
  2467.       (height != last_height))
  2468.     {
  2469.       if (g_editor->preview_rows[0])
  2470.     g_free (g_editor->preview_rows[0]);
  2471.  
  2472.       if (g_editor->preview_rows[1])
  2473.     g_free (g_editor->preview_rows[1]);
  2474.  
  2475.       rowsiz = width * 3 * sizeof (guchar);
  2476.  
  2477.       g_editor->preview_rows[0] = g_malloc (rowsiz);
  2478.       g_editor->preview_rows[1] = g_malloc (rowsiz);
  2479.  
  2480.       recalculate = TRUE; /* Force recalculation */
  2481.     }
  2482.  
  2483.   last_width = width;
  2484.   last_height = height;
  2485.  
  2486.   /* Have to redraw? */
  2487.   if (recalculate)
  2488.     {
  2489.       adjustment = GTK_ADJUSTMENT (g_editor->scroll_data);
  2490.  
  2491.       preview_fill_image (width, height,
  2492.               adjustment->value,
  2493.               adjustment->value + adjustment->page_size);
  2494.  
  2495.       gtk_widget_draw (g_editor->preview, NULL);
  2496.     }
  2497. }
  2498.  
  2499. /*****/
  2500.  
  2501. static void
  2502. preview_fill_image (gint    width,
  2503.             gint    height,
  2504.             gdouble left,
  2505.             gdouble right)
  2506. {
  2507.   guchar  *p0, *p1;
  2508.   gint     x, y;
  2509.   gdouble  dx, cur_x;
  2510.   gdouble  r, g, b, a;
  2511.   gdouble  c0, c1;
  2512.  
  2513.   dx    = (right - left) / (width - 1);
  2514.   cur_x = left;
  2515.   p0    = g_editor->preview_rows[0];
  2516.   p1    = g_editor->preview_rows[1];
  2517.  
  2518.   /* Create lines to fill the image */
  2519.   for (x = 0; x < width; x++)
  2520.     {
  2521.       gradient_get_color_at (curr_gradient, cur_x, &r, &g, &b, &a);
  2522.  
  2523.       if ((x / GIMP_CHECK_SIZE) & 1)
  2524.     {
  2525.       c0 = GIMP_CHECK_LIGHT;
  2526.       c1 = GIMP_CHECK_DARK;
  2527.     }
  2528.       else
  2529.     {
  2530.       c0 = GIMP_CHECK_DARK;
  2531.       c1 = GIMP_CHECK_LIGHT;
  2532.     }
  2533.  
  2534.       *p0++ = (c0 + (r - c0) * a) * 255.0;
  2535.       *p0++ = (c0 + (g - c0) * a) * 255.0;
  2536.       *p0++ = (c0 + (b - c0) * a) * 255.0;
  2537.  
  2538.       *p1++ = (c1 + (r - c1) * a) * 255.0;
  2539.       *p1++ = (c1 + (g - c1) * a) * 255.0;
  2540.       *p1++ = (c1 + (b - c1) * a) * 255.0;
  2541.  
  2542.       cur_x += dx;
  2543.     }
  2544.  
  2545.   /* Fill image */
  2546.   for (y = 0; y < height; y++)
  2547.     {
  2548.       if ((y / GIMP_CHECK_SIZE) & 1)
  2549.     gtk_preview_draw_row (GTK_PREVIEW (g_editor->preview),
  2550.                   g_editor->preview_rows[1], 0, y, width);
  2551.       else
  2552.     gtk_preview_draw_row (GTK_PREVIEW (g_editor->preview),
  2553.                   g_editor->preview_rows[0], 0, y, width);
  2554.     }
  2555. }
  2556.  
  2557. /***** Gradient control functions *****/
  2558.  
  2559. /* *** WARNING *** WARNING *** WARNING ***
  2560.  *
  2561.  * All the event-handling code for the gradient control widget is
  2562.  * extremely hairy.  You are not expected to understand it.  If you
  2563.  * find bugs, mail me unless you are very brave and you want to fix
  2564.  * them yourself ;-)
  2565.  */
  2566.  
  2567. static gint
  2568. control_events (GtkWidget *widget,
  2569.         GdkEvent  *event,
  2570.         gpointer   data)
  2571. {
  2572.   GdkEventButton *bevent;
  2573.   grad_segment_t *seg;
  2574.   gint            x, y;
  2575.   guint32         time;
  2576.  
  2577.   switch (event->type)
  2578.     {
  2579.     case GDK_EXPOSE:
  2580.       control_update (FALSE);
  2581.       break;
  2582.  
  2583.     case GDK_LEAVE_NOTIFY:
  2584.       ed_set_hint ("");
  2585.       break;
  2586.  
  2587.     case GDK_BUTTON_PRESS:
  2588.       if (g_editor->control_drag_mode == GRAD_DRAG_NONE)
  2589.     {
  2590.       gtk_widget_get_pointer (g_editor->control, &x, &y);
  2591.  
  2592.       bevent = (GdkEventButton *) event;
  2593.  
  2594.       g_editor->control_last_x     = x;
  2595.       g_editor->control_click_time = bevent->time;
  2596.  
  2597.       control_button_press (x, y, bevent->button, bevent->state);
  2598.  
  2599.       if (g_editor->control_drag_mode != GRAD_DRAG_NONE)
  2600.         gtk_grab_add (widget);
  2601.     }
  2602.       break;
  2603.  
  2604.     case GDK_BUTTON_RELEASE:
  2605.       ed_set_hint ("");
  2606.  
  2607.       if (g_editor->control_drag_mode != GRAD_DRAG_NONE)
  2608.     {
  2609.       gtk_grab_remove (widget);
  2610.  
  2611.       gtk_widget_get_pointer (g_editor->control, &x, &y);
  2612.  
  2613.       time = ((GdkEventButton *) event)->time;
  2614.  
  2615.       if ((time - g_editor->control_click_time) >= GRAD_MOVE_TIME)
  2616.         {
  2617.           ed_update_editor (GRAD_UPDATE_GRADIENT); /* Possible move */
  2618.         }
  2619.       else if ((g_editor->control_drag_mode == GRAD_DRAG_MIDDLE) ||
  2620.            (g_editor->control_drag_mode == GRAD_DRAG_ALL))
  2621.         {
  2622.           seg = g_editor->control_drag_segment;
  2623.  
  2624.           if ((g_editor->control_drag_mode == GRAD_DRAG_ALL) &&
  2625.           g_editor->control_compress)
  2626.         control_extend_selection (seg, control_calc_g_pos (x));
  2627.           else
  2628.         control_select_single_segment (seg);
  2629.  
  2630.           ed_update_editor (GRAD_UPDATE_CONTROL);
  2631.         }
  2632.  
  2633.       g_editor->control_drag_mode = GRAD_DRAG_NONE;
  2634.       g_editor->control_compress  = FALSE;
  2635.  
  2636.       control_do_hint (x, y);
  2637.     }
  2638.       break;
  2639.  
  2640.     case GDK_MOTION_NOTIFY:
  2641.       gtk_widget_get_pointer (g_editor->control, &x, &y);
  2642.  
  2643.       if (x != g_editor->control_last_x)
  2644.     {
  2645.       g_editor->control_last_x = x;
  2646.  
  2647.       if (g_editor->control_drag_mode != GRAD_DRAG_NONE)
  2648.         {
  2649.           time = ((GdkEventButton *) event)->time;
  2650.  
  2651.           if ((time - g_editor->control_click_time) >= GRAD_MOVE_TIME)
  2652.         control_motion(x);
  2653.         }
  2654.       else
  2655.         {
  2656.           ed_update_editor (GRAD_UPDATE_CONTROL);
  2657.  
  2658.           control_do_hint (x, y);
  2659.         }
  2660.     }
  2661.       break;
  2662.  
  2663.     default:
  2664.       break;
  2665.     }
  2666.  
  2667.   return FALSE;
  2668. }
  2669.  
  2670. /*****/
  2671.  
  2672. static void
  2673. control_do_hint (gint x,
  2674.          gint y)
  2675. {
  2676.   grad_segment_t      *seg;
  2677.   control_drag_mode_t  handle;
  2678.   gboolean             in_handle;
  2679.   double               pos;
  2680.  
  2681.   pos = control_calc_g_pos (x);
  2682.  
  2683.   if ((pos < 0.0) || (pos > 1.0))
  2684.     return;
  2685.  
  2686.   seg_get_closest_handle (curr_gradient, pos, &seg, &handle);
  2687.  
  2688.   in_handle = control_point_in_handle (x, y, seg, handle);
  2689.  
  2690.   if (in_handle)
  2691.     {
  2692.       switch (handle)
  2693.     {
  2694.     case GRAD_DRAG_LEFT:
  2695.       if (seg != NULL)
  2696.         {
  2697.           if (seg->prev != NULL)
  2698.         ed_set_hint (_("Drag: move    Shift+drag: move & compress"));
  2699.           else
  2700.         ed_set_hint (_("Click: select    Shift+click: extend selection"));
  2701.         }
  2702.       else
  2703.         {
  2704.           ed_set_hint (_("Click: select    Shift+click: extend selection"));
  2705.         }
  2706.  
  2707.       break;
  2708.  
  2709.     case GRAD_DRAG_MIDDLE:
  2710.       ed_set_hint (_("Click: select    Shift+click: extend selection    "
  2711.              "Drag: move"));
  2712.  
  2713.       break;
  2714.  
  2715.     default:
  2716.       g_warning ("in_handle is true yet we got handle type %d",
  2717.              (int) handle);
  2718.       break;
  2719.     }
  2720.     }
  2721.   else
  2722.     ed_set_hint (_("Click: select    Shift+click: extend selection    "
  2723.            "Drag: move    Shift+drag: move & compress"));
  2724. }
  2725.  
  2726. /*****/
  2727.  
  2728. static void
  2729. control_button_press (gint  x,
  2730.               gint  y,
  2731.               guint button,
  2732.               guint state)
  2733. {
  2734.   grad_segment_t      *seg;
  2735.   control_drag_mode_t  handle;
  2736.   gdouble              xpos;
  2737.   gboolean             in_handle;
  2738.  
  2739.   /* See which button was pressed */
  2740.  
  2741.   if (curr_gradient == NULL)
  2742.     return;
  2743.   
  2744.   switch (button)
  2745.     {
  2746.     case 1:
  2747.       break;
  2748.  
  2749.     case 3:
  2750.       cpopup_do_popup();
  2751.       return;
  2752.  
  2753.       /*  wheelmouse support  */
  2754.     case 4:
  2755.       {
  2756.     GtkAdjustment *adj = GTK_ADJUSTMENT (g_editor->scroll_data);
  2757.     gfloat new_value   = adj->value - adj->page_increment / 2;
  2758.  
  2759.     new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
  2760.     gtk_adjustment_set_value (adj, new_value);
  2761.       }
  2762.       return;
  2763.  
  2764.     case 5:
  2765.       {
  2766.     GtkAdjustment *adj = GTK_ADJUSTMENT (g_editor->scroll_data);
  2767.     gfloat new_value   = adj->value + adj->page_increment / 2;
  2768.  
  2769.     new_value = CLAMP (new_value, adj->lower, adj->upper - adj->page_size);
  2770.     gtk_adjustment_set_value (adj, new_value);
  2771.       }
  2772.       return;
  2773.  
  2774.     default:
  2775.       return;
  2776.     }
  2777.  
  2778.   /* Find the closest handle */
  2779.  
  2780.   xpos = control_calc_g_pos (x);
  2781.  
  2782.   seg_get_closest_handle (curr_gradient, xpos, &seg, &handle);
  2783.  
  2784.   in_handle = control_point_in_handle (x, y, seg, handle);
  2785.  
  2786.   /* Now see what we have */
  2787.  
  2788.   if (in_handle)
  2789.     {
  2790.       switch (handle)
  2791.     {
  2792.     case GRAD_DRAG_LEFT:
  2793.       if (seg != NULL)
  2794.         {
  2795.           /* Left handle of some segment */
  2796.           if (state & GDK_SHIFT_MASK)
  2797.         {
  2798.           if (seg->prev != NULL)
  2799.             {
  2800.               g_editor->control_drag_mode    = GRAD_DRAG_LEFT;
  2801.               g_editor->control_drag_segment = seg;
  2802.               g_editor->control_compress     = TRUE;
  2803.             }
  2804.           else
  2805.             {
  2806.               control_extend_selection (seg, xpos);
  2807.               ed_update_editor (GRAD_UPDATE_CONTROL);
  2808.             }
  2809.         }
  2810.           else if (seg->prev != NULL)
  2811.         {
  2812.           g_editor->control_drag_mode    = GRAD_DRAG_LEFT;
  2813.           g_editor->control_drag_segment = seg;
  2814.         }
  2815.           else
  2816.         {
  2817.           control_select_single_segment (seg);
  2818.           ed_update_editor (GRAD_UPDATE_CONTROL);
  2819.         }
  2820.  
  2821.           return;
  2822.         }
  2823.       else  /* seg == NULL */
  2824.         {
  2825.           /* Right handle of last segment */
  2826.           seg = seg_get_last_segment (curr_gradient->segments);
  2827.  
  2828.           if (state & GDK_SHIFT_MASK)
  2829.         {
  2830.           control_extend_selection (seg, xpos);
  2831.           ed_update_editor (GRAD_UPDATE_CONTROL);
  2832.         }
  2833.           else
  2834.         {
  2835.           control_select_single_segment (seg);
  2836.           ed_update_editor (GRAD_UPDATE_CONTROL);
  2837.         }
  2838.  
  2839.           return;
  2840.         }
  2841.  
  2842.       break;
  2843.  
  2844.     case GRAD_DRAG_MIDDLE:
  2845.       if (state & GDK_SHIFT_MASK)
  2846.         {
  2847.           control_extend_selection (seg, xpos);
  2848.           ed_update_editor (GRAD_UPDATE_CONTROL);
  2849.         }
  2850.       else
  2851.         {
  2852.           g_editor->control_drag_mode    = GRAD_DRAG_MIDDLE;
  2853.           g_editor->control_drag_segment = seg;
  2854.         }
  2855.  
  2856.       return;
  2857.  
  2858.     default:
  2859.       g_warning ("in_handle is true yet we got handle type %d",
  2860.              (int) handle);
  2861.       return;
  2862.     }
  2863.     }
  2864.   else  /* !in_handle */
  2865.     {
  2866.       seg = seg_get_segment_at (curr_gradient, xpos);
  2867.  
  2868.       g_editor->control_drag_mode    = GRAD_DRAG_ALL;
  2869.       g_editor->control_drag_segment = seg;
  2870.       g_editor->control_last_gx      = xpos;
  2871.       g_editor->control_orig_pos     = xpos;
  2872.  
  2873.       if (state & GDK_SHIFT_MASK)
  2874.     g_editor->control_compress = TRUE;
  2875.  
  2876.       return;
  2877.     }
  2878. }
  2879.  
  2880. /*****/
  2881.  
  2882. static gboolean
  2883. control_point_in_handle (gint                 x,
  2884.              gint                 y,
  2885.              grad_segment_t      *seg,
  2886.              control_drag_mode_t  handle)
  2887. {
  2888.   gint handle_pos;
  2889.  
  2890.   switch (handle)
  2891.     {
  2892.     case GRAD_DRAG_LEFT:
  2893.       if (seg)
  2894.     {
  2895.       handle_pos = control_calc_p_pos (seg->left);
  2896.     }
  2897.       else
  2898.     {
  2899.       seg = seg_get_last_segment (curr_gradient->segments);
  2900.  
  2901.       handle_pos = control_calc_p_pos (seg->right);
  2902.     }
  2903.  
  2904.       break;
  2905.  
  2906.     case GRAD_DRAG_MIDDLE:
  2907.       handle_pos = control_calc_p_pos (seg->middle);
  2908.       break;
  2909.  
  2910.     default:
  2911.       g_warning ("can not handle drag mode %d", (gint) handle);
  2912.       return FALSE;
  2913.     }
  2914.  
  2915.   y /= 2;
  2916.  
  2917.   if ((x >= (handle_pos - y)) && (x <= (handle_pos + y)))
  2918.     return TRUE;
  2919.   else
  2920.     return FALSE;
  2921. }
  2922.  
  2923. /*****/
  2924.  
  2925. static void
  2926. control_select_single_segment (grad_segment_t *seg)
  2927. {
  2928.   g_editor->control_sel_l = seg;
  2929.   g_editor->control_sel_r = seg;
  2930. }
  2931.  
  2932. /*****/
  2933.  
  2934. static void
  2935. control_extend_selection (grad_segment_t *seg,
  2936.               double          pos)
  2937. {
  2938.   if (fabs (pos - g_editor->control_sel_l->left) <
  2939.       fabs (pos - g_editor->control_sel_r->right))
  2940.     g_editor->control_sel_l = seg;
  2941.   else
  2942.     g_editor->control_sel_r = seg;
  2943. }
  2944.  
  2945. /*****/
  2946.  
  2947. static void
  2948. control_motion (gint x)
  2949. {
  2950.   grad_segment_t *seg;
  2951.   gdouble         pos;
  2952.   gdouble         delta;
  2953.   gchar          *str = NULL;
  2954.  
  2955.   seg = g_editor->control_drag_segment;
  2956.  
  2957.   switch (g_editor->control_drag_mode)
  2958.     {
  2959.     case GRAD_DRAG_LEFT:
  2960.       pos = control_calc_g_pos (x);
  2961.  
  2962.       if (!g_editor->control_compress)
  2963.     seg->prev->right = seg->left = CLAMP (pos,
  2964.                           seg->prev->middle + EPSILON,
  2965.                           seg->middle - EPSILON);
  2966.       else
  2967.     control_compress_left (g_editor->control_sel_l,
  2968.                    g_editor->control_sel_r,
  2969.                    seg, pos);
  2970.  
  2971.       str = g_strdup_printf (_("Handle position: %0.6f"), seg->left);
  2972.       ed_set_hint (str);
  2973.  
  2974.       break;
  2975.  
  2976.     case GRAD_DRAG_MIDDLE:
  2977.       pos = control_calc_g_pos (x);
  2978.       seg->middle = CLAMP (pos, seg->left + EPSILON, seg->right - EPSILON);
  2979.  
  2980.       str = g_strdup_printf (_("Handle position: %0.6f"), seg->middle);
  2981.       ed_set_hint (str);
  2982.  
  2983.       break;
  2984.  
  2985.     case GRAD_DRAG_ALL:
  2986.       pos    = control_calc_g_pos (x);
  2987.       delta  = pos - g_editor->control_last_gx;
  2988.  
  2989.       if ((seg->left >= g_editor->control_sel_l->left) &&
  2990.       (seg->right <= g_editor->control_sel_r->right))
  2991.     delta = control_move (g_editor->control_sel_l,
  2992.                   g_editor->control_sel_r, delta);
  2993.       else
  2994.     delta = control_move (seg, seg, delta);
  2995.  
  2996.       g_editor->control_last_gx += delta;
  2997.  
  2998.       str = g_strdup_printf (_("Distance: %0.6f"),
  2999.                  g_editor->control_last_gx - g_editor->control_orig_pos);
  3000.       ed_set_hint (str);
  3001.  
  3002.       break;
  3003.  
  3004.     default:
  3005.       gimp_fatal_error ("Attempt to move bogus handle %d",
  3006.             (gint) g_editor->control_drag_mode);
  3007.       break;
  3008.     }
  3009.  
  3010.   if (str)
  3011.     g_free (str);
  3012.  
  3013.   curr_gradient->dirty = TRUE;
  3014.  
  3015.   if (g_editor->instant_update)
  3016.     ed_update_editor (GRAD_UPDATE_GRADIENT | GRAD_UPDATE_CONTROL);
  3017.   else
  3018.     ed_update_editor (GRAD_UPDATE_CONTROL);
  3019. }
  3020.  
  3021. /*****/
  3022.  
  3023. static void
  3024. control_compress_left (grad_segment_t *range_l,
  3025.                grad_segment_t *range_r,
  3026.                grad_segment_t *drag_seg,
  3027.                double          pos)
  3028. {
  3029.   grad_segment_t *seg;
  3030.   gdouble         lbound, rbound;
  3031.   gint            k;
  3032.  
  3033.   /* Check what we have to compress */
  3034.  
  3035.   if (!((drag_seg->left >= range_l->left) &&
  3036.     ((drag_seg->right <= range_r->right) || (drag_seg == range_r->next))))
  3037.     {
  3038.       /* We are compressing a segment outside the selection */
  3039.  
  3040.       range_l = range_r = drag_seg;
  3041.     }
  3042.  
  3043.   /* Calculate left bound for dragged hadle */
  3044.  
  3045.   if (drag_seg == range_l)
  3046.     lbound = range_l->prev->left + 2.0 * EPSILON;
  3047.   else
  3048.     {
  3049.       /* Count number of segments to the left of the dragged handle */
  3050.  
  3051.       seg = drag_seg;
  3052.       k   = 0;
  3053.  
  3054.       while (seg != range_l)
  3055.     {
  3056.       k++;
  3057.       seg = seg->prev;
  3058.     }
  3059.  
  3060.       /* 2*k handles have to fit */
  3061.  
  3062.       lbound = range_l->left + 2.0 * k * EPSILON;
  3063.     }
  3064.  
  3065.   /* Calculate right bound for dragged handle */
  3066.  
  3067.   if (drag_seg == range_r->next)
  3068.     rbound = range_r->next->right - 2.0 * EPSILON;
  3069.   else
  3070.     {
  3071.       /* Count number of segments to the right of the dragged handle */
  3072.  
  3073.       seg = drag_seg;
  3074.       k   = 1;
  3075.  
  3076.       while (seg != range_r)
  3077.     {
  3078.       k++;
  3079.       seg = seg->next;
  3080.     }
  3081.  
  3082.       /* 2*k handles have to fit */
  3083.  
  3084.       rbound = range_r->right - 2.0 * k * EPSILON;
  3085.     }
  3086.  
  3087.   /* Calculate position */
  3088.  
  3089.   pos = CLAMP (pos, lbound, rbound);
  3090.  
  3091.   /* Compress segments to the left of the handle */
  3092.  
  3093.   if (drag_seg == range_l)
  3094.     control_compress_range (range_l->prev, range_l->prev,
  3095.                 range_l->prev->left, pos);
  3096.   else
  3097.     control_compress_range (range_l, drag_seg->prev, range_l->left, pos);
  3098.  
  3099.   /* Compress segments to the right of the handle */
  3100.  
  3101.   if (drag_seg != range_r->next)
  3102.     control_compress_range (drag_seg, range_r, pos, range_r->right);
  3103.   else
  3104.     control_compress_range (drag_seg, drag_seg, pos, drag_seg->right);
  3105. }
  3106.  
  3107. /*****/
  3108.  
  3109. static void
  3110. control_compress_range (grad_segment_t *range_l,
  3111.             grad_segment_t *range_r,
  3112.             gdouble         new_l,
  3113.             gdouble         new_r)
  3114. {
  3115.   gdouble         orig_l, orig_r;
  3116.   gdouble         scale;
  3117.   grad_segment_t *seg, *aseg;
  3118.  
  3119.   orig_l = range_l->left;
  3120.   orig_r = range_r->right;
  3121.  
  3122.   scale = (new_r - new_l) / (orig_r - orig_l);
  3123.  
  3124.   seg = range_l;
  3125.  
  3126.   do
  3127.     {
  3128.       if (seg->prev)
  3129.         seg->left = new_l + (seg->left - orig_l) * scale;
  3130.  
  3131.       seg->middle = new_l + (seg->middle - orig_l) * scale;
  3132.  
  3133.       if (seg->next)
  3134.         seg->right = new_l + (seg->right - orig_l) * scale;
  3135.  
  3136.       /* Next */
  3137.  
  3138.       aseg = seg;
  3139.       seg  = seg->next;
  3140.     }
  3141.   while (aseg != range_r);
  3142. }
  3143.  
  3144. /*****/
  3145.  
  3146. static gdouble
  3147. control_move (grad_segment_t *range_l,
  3148.           grad_segment_t *range_r,
  3149.           gdouble         delta)
  3150. {
  3151.   gdouble         lbound, rbound;
  3152.   gint            is_first, is_last;
  3153.   grad_segment_t *seg, *aseg;
  3154.  
  3155.   /* First or last segments in gradient? */
  3156.  
  3157.   is_first = (range_l->prev == NULL);
  3158.   is_last  = (range_r->next == NULL);
  3159.  
  3160.   /* Calculate drag bounds */
  3161.  
  3162.   if (!g_editor->control_compress)
  3163.     {
  3164.       if (!is_first)
  3165.     lbound = range_l->prev->middle + EPSILON;
  3166.       else
  3167.     lbound = range_l->left + EPSILON;
  3168.  
  3169.       if (!is_last)
  3170.     rbound = range_r->next->middle - EPSILON;
  3171.       else
  3172.     rbound = range_r->right - EPSILON;
  3173.     }
  3174.   else
  3175.     {
  3176.       if (!is_first)
  3177.     lbound = range_l->prev->left + 2.0 * EPSILON;
  3178.       else
  3179.     lbound = range_l->left + EPSILON;
  3180.  
  3181.       if (!is_last)
  3182.     rbound = range_r->next->right - 2.0 * EPSILON;
  3183.       else
  3184.     rbound = range_r->right - EPSILON;
  3185.     }
  3186.  
  3187.   /* Fix the delta if necessary */
  3188.  
  3189.   if (delta < 0.0)
  3190.     {
  3191.       if (!is_first)
  3192.     {
  3193.       if (range_l->left + delta < lbound)
  3194.         delta = lbound - range_l->left;
  3195.     }
  3196.       else
  3197.     if (range_l->middle + delta < lbound)
  3198.       delta = lbound - range_l->middle;
  3199.     }
  3200.   else
  3201.     {
  3202.       if (!is_last)
  3203.     {
  3204.       if (range_r->right + delta > rbound)
  3205.         delta = rbound - range_r->right;
  3206.     }
  3207.       else
  3208.     if (range_r->middle + delta > rbound)
  3209.       delta = rbound - range_r->middle;
  3210.     }
  3211.  
  3212.   /* Move all the segments inside the range */
  3213.  
  3214.   seg = range_l;
  3215.  
  3216.   do
  3217.     {
  3218.       if (!((seg == range_l) && is_first))
  3219.     seg->left   += delta;
  3220.  
  3221.       seg->middle += delta;
  3222.  
  3223.       if (!((seg == range_r) && is_last))
  3224.     seg->right  += delta;
  3225.  
  3226.       /* Next */
  3227.  
  3228.       aseg = seg;
  3229.       seg  = seg->next;
  3230.     }
  3231.   while (aseg != range_r);
  3232.  
  3233.   /* Fix the segments that surround the range */
  3234.  
  3235.   if (!is_first)
  3236.     {
  3237.       if (!g_editor->control_compress)
  3238.     range_l->prev->right = range_l->left;
  3239.       else
  3240.     control_compress_range (range_l->prev, range_l->prev,
  3241.                 range_l->prev->left, range_l->left);
  3242.     }
  3243.  
  3244.   if (!is_last)
  3245.     {
  3246.       if (!g_editor->control_compress)
  3247.     range_r->next->left = range_r->right;
  3248.       else
  3249.     control_compress_range (range_r->next, range_r->next,
  3250.                 range_r->right, range_r->next->right);
  3251.     }
  3252.  
  3253.   return delta;
  3254. }
  3255.  
  3256. /*****/
  3257.  
  3258. static void
  3259. control_update (gboolean recalculate)
  3260. {
  3261.   GtkAdjustment *adjustment;
  3262.   gint           cwidth, cheight;
  3263.   gint           pwidth, pheight;
  3264.  
  3265.   /* We only update if we can redraw and a gradient is present */
  3266.   if (curr_gradient == NULL) 
  3267.     return;
  3268.  
  3269.   if (! GTK_WIDGET_DRAWABLE (g_editor->control))
  3270.     return;
  3271.  
  3272.   /*  See whether we have to re-create the control pixmap
  3273.    *  depending on the preview's width
  3274.    */
  3275.   cwidth  = g_editor->preview->allocation.width;
  3276.   cheight = GRAD_CONTROL_HEIGHT;
  3277.  
  3278.   if (g_editor->control_pixmap)
  3279.     gdk_window_get_size (g_editor->control_pixmap, &pwidth, &pheight);
  3280.  
  3281.   if (!g_editor->control_pixmap ||
  3282.       (cwidth != pwidth) ||
  3283.       (cheight != pheight))
  3284.     {
  3285.       if (g_editor->control_pixmap)
  3286.     gdk_pixmap_unref (g_editor->control_pixmap);
  3287.  
  3288.       g_editor->control_pixmap =
  3289.     gdk_pixmap_new (g_editor->control->window, cwidth, cheight, -1);
  3290.  
  3291.       recalculate = TRUE;
  3292.     }
  3293.  
  3294.   /* Avaoid segfault on first invocation */
  3295.   if (cwidth < GRAD_PREVIEW_WIDTH)
  3296.     return;
  3297.  
  3298.   /* Have to reset the selection? */
  3299.   if (recalculate)
  3300.     control_select_single_segment (curr_gradient->segments);
  3301.  
  3302.   /* Redraw pixmap */
  3303.   adjustment = GTK_ADJUSTMENT (g_editor->scroll_data);
  3304.  
  3305.   control_draw (g_editor->control_pixmap,
  3306.         cwidth, cheight,
  3307.         adjustment->value,
  3308.         adjustment->value + adjustment->page_size);
  3309.  
  3310.   gdk_draw_pixmap (g_editor->control->window, g_editor->control->style->black_gc,
  3311.            g_editor->control_pixmap, 0, 0, 0, 0, cwidth, cheight);
  3312. }
  3313.  
  3314. /*****/
  3315.  
  3316. static void
  3317. control_draw (GdkPixmap *pixmap,
  3318.           gint       width,
  3319.           gint       height,
  3320.           gdouble    left,
  3321.           gdouble    right)
  3322. {
  3323.   gint                    sel_l, sel_r;
  3324.   gdouble              g_pos;
  3325.   grad_segment_t      *seg;
  3326.   control_drag_mode_t  handle;
  3327.  
  3328.   /* Clear the pixmap */
  3329.  
  3330.   gdk_draw_rectangle (pixmap, g_editor->control->style->bg_gc[GTK_STATE_NORMAL],
  3331.               TRUE, 0, 0, width, height);
  3332.  
  3333.   /* Draw selection */
  3334.  
  3335.   sel_l = control_calc_p_pos (g_editor->control_sel_l->left);
  3336.   sel_r = control_calc_p_pos (g_editor->control_sel_r->right);
  3337.  
  3338.   gdk_draw_rectangle (pixmap,
  3339.               g_editor->control->style->dark_gc[GTK_STATE_NORMAL],
  3340.               TRUE, sel_l, 0, sel_r - sel_l + 1, height);
  3341.  
  3342.   /* Draw handles */
  3343.  
  3344.   seg = curr_gradient->segments;
  3345.  
  3346.   while (seg)
  3347.     {
  3348.       control_draw_normal_handle (pixmap, seg->left, height);
  3349.       control_draw_middle_handle (pixmap, seg->middle, height);
  3350.  
  3351.       /* Draw right handle only if this is the last segment */
  3352.  
  3353.       if (seg->next == NULL)
  3354.     control_draw_normal_handle (pixmap, seg->right, height);
  3355.  
  3356.       /* Next! */
  3357.  
  3358.       seg = seg->next;
  3359.     }
  3360.  
  3361.   /* Draw the handle which is closest to the mouse position */
  3362.  
  3363.   g_pos = control_calc_g_pos (g_editor->control_last_x);
  3364.  
  3365.   seg_get_closest_handle (curr_gradient, CLAMP (g_pos, 0.0, 1.0), &seg, &handle);
  3366.  
  3367.   switch (handle)
  3368.     {
  3369.     case GRAD_DRAG_LEFT:
  3370.       if (seg)
  3371.     {
  3372.       control_draw_normal_handle (pixmap, seg->left, height);
  3373.     }
  3374.       else
  3375.     {
  3376.       seg = seg_get_last_segment (curr_gradient->segments);
  3377.  
  3378.       control_draw_normal_handle (pixmap, seg->right, height);
  3379.     }
  3380.  
  3381.       break;
  3382.  
  3383.     case GRAD_DRAG_MIDDLE:
  3384.       control_draw_middle_handle (pixmap, seg->middle, height);
  3385.       break;
  3386.  
  3387.     default:
  3388.       break;
  3389.     }
  3390. }
  3391.  
  3392. /*****/
  3393.  
  3394. static void
  3395. control_draw_normal_handle (GdkPixmap *pixmap,
  3396.                 gdouble    pos,
  3397.                 gint       height)
  3398. {
  3399.   control_draw_handle (pixmap,
  3400.                g_editor->control->style->black_gc,
  3401.                g_editor->control->style->black_gc,
  3402.                control_calc_p_pos (pos), height);
  3403. }
  3404.  
  3405. static void
  3406. control_draw_middle_handle (GdkPixmap *pixmap,
  3407.                 gdouble    pos,
  3408.                 gint       height)
  3409. {
  3410.   control_draw_handle (pixmap,
  3411.                g_editor->control->style->black_gc,
  3412.                g_editor->control->style->bg_gc[GTK_STATE_PRELIGHT],
  3413.                control_calc_p_pos(pos), height);
  3414. }
  3415.  
  3416. static void
  3417. control_draw_handle (GdkPixmap *pixmap,
  3418.              GdkGC     *border_gc,
  3419.              GdkGC     *fill_gc,
  3420.              gint       xpos,
  3421.              gint       height)
  3422. {
  3423.   gint y;
  3424.   gint left, right, bottom;
  3425.  
  3426.   for (y = 0; y < height; y++)
  3427.     gdk_draw_line (pixmap, fill_gc, xpos - y / 2, y, xpos + y / 2, y);
  3428.  
  3429.   bottom = height - 1;
  3430.   left   = xpos - bottom / 2;
  3431.   right  = xpos + bottom / 2;
  3432.  
  3433.   gdk_draw_line (pixmap, border_gc, xpos, 0, left, bottom);
  3434.   gdk_draw_line (pixmap, border_gc, xpos, 0, right, bottom);
  3435.   gdk_draw_line (pixmap, border_gc, left, bottom, right, bottom);
  3436. }
  3437.  
  3438. /*****/
  3439.  
  3440. static gint
  3441. control_calc_p_pos (gdouble pos)
  3442. {
  3443.   gint           pwidth, pheight;
  3444.   GtkAdjustment *adjustment;
  3445.  
  3446.   /* Calculate the position (in widget's coordinates) of the
  3447.    * requested point from the gradient.  Rounding is done to
  3448.    * minimize mismatches between the rendered gradient preview
  3449.    * and the gradient control's handles.
  3450.    */
  3451.  
  3452.   adjustment = GTK_ADJUSTMENT (g_editor->scroll_data);
  3453.   gdk_window_get_size (g_editor->control_pixmap, &pwidth, &pheight);
  3454.  
  3455.   return RINT ((pwidth - 1) * (pos - adjustment->value) / adjustment->page_size);
  3456. }
  3457.  
  3458. /*****/
  3459.  
  3460. static gdouble
  3461. control_calc_g_pos (gint pos)
  3462. {
  3463.   gint           pwidth, pheight;
  3464.   GtkAdjustment *adjustment;
  3465.  
  3466.   /* Calculate the gradient position that corresponds to widget's coordinates */
  3467.  
  3468.   adjustment = GTK_ADJUSTMENT (g_editor->scroll_data);
  3469.   gdk_window_get_size (g_editor->control_pixmap, &pwidth, &pheight);
  3470.  
  3471.   return adjustment->page_size * pos / (pwidth - 1) + adjustment->value;
  3472. }
  3473.  
  3474. /***** Control popup functions *****/
  3475.  
  3476. static void
  3477. cpopup_create_main_menu (void)
  3478. {
  3479.   GtkWidget     *menu;
  3480.   GtkWidget     *menuitem;
  3481.   GtkWidget     *label;
  3482.   GtkAccelGroup *accel_group;
  3483.  
  3484.   menu = gtk_menu_new ();
  3485.   accel_group = gtk_accel_group_new ();
  3486.  
  3487.   g_editor->accel_group = accel_group;
  3488.  
  3489.   gtk_menu_set_accel_group (GTK_MENU (menu), accel_group);
  3490.   gtk_window_add_accel_group (GTK_WINDOW (g_editor->shell), accel_group);
  3491.  
  3492.   /* Left endpoint */
  3493.   menuitem = cpopup_create_color_item (&g_editor->left_color_preview, &label);
  3494.   gtk_label_set_text (GTK_LABEL (label), _("Left endpoint's color"));
  3495.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  3496.               (GtkSignalFunc) cpopup_set_left_color_callback,
  3497.               NULL);
  3498.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3499.   gtk_widget_show (menuitem);
  3500.   gtk_widget_add_accelerator (menuitem, "activate",
  3501.                   accel_group,
  3502.                   'L', 0,
  3503.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  3504.  
  3505.   menuitem = gtk_menu_item_new_with_label (_("Load from"));
  3506.   g_editor->control_left_load_popup =
  3507.     cpopup_create_load_menu (g_editor->left_load_color_boxes,
  3508.                  g_editor->left_load_labels,
  3509.                  _("Left neighbor's right endpoint"),
  3510.                  _("Right endpoint"),
  3511.                  (GtkSignalFunc) cpopup_load_left_callback,
  3512.                  'L', GDK_CONTROL_MASK,
  3513.                  'L', GDK_MOD1_MASK,
  3514.                  'F', GDK_CONTROL_MASK);
  3515.   gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem),
  3516.                  g_editor->control_left_load_popup);
  3517.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3518.   gtk_widget_show (menuitem);
  3519.  
  3520.   menuitem = gtk_menu_item_new_with_label (_("Save to"));
  3521.   g_editor->control_left_save_popup =
  3522.     cpopup_create_save_menu (g_editor->left_save_color_boxes,
  3523.                  g_editor->left_save_labels,
  3524.                  (GtkSignalFunc) cpopup_save_left_callback);
  3525.   gtk_menu_item_set_submenu (GTK_MENU_ITEM(menuitem),
  3526.                  g_editor->control_left_save_popup);
  3527.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3528.   gtk_widget_show (menuitem);
  3529.  
  3530.   /* Right endpoint */
  3531.   menuitem = gtk_menu_item_new ();
  3532.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3533.   gtk_widget_show (menuitem);
  3534.  
  3535.   menuitem = cpopup_create_color_item (&g_editor->right_color_preview, &label);
  3536.   gtk_label_set_text (GTK_LABEL (label), _("Right endpoint's color"));
  3537.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  3538.               (GtkSignalFunc) cpopup_set_right_color_callback,
  3539.               NULL);
  3540.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3541.   gtk_widget_show (menuitem);
  3542.   gtk_widget_add_accelerator (menuitem, "activate",
  3543.                   accel_group,
  3544.                   'R', 0,
  3545.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  3546.  
  3547.   menuitem = gtk_menu_item_new_with_label (_("Load from"));
  3548.   g_editor->control_right_load_popup =
  3549.     cpopup_create_load_menu (g_editor->right_load_color_boxes,
  3550.                  g_editor->right_load_labels,
  3551.                  _("Right neighbor's left endpoint"),
  3552.                  _("Left endpoint"),
  3553.                  (GtkSignalFunc) cpopup_load_right_callback,
  3554.                  'R', GDK_CONTROL_MASK,
  3555.                  'R', GDK_MOD1_MASK,
  3556.                  'F', GDK_MOD1_MASK);
  3557.   gtk_menu_item_set_submenu (GTK_MENU_ITEM(menuitem),
  3558.                  g_editor->control_right_load_popup);
  3559.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3560.   gtk_widget_show (menuitem);
  3561.  
  3562.   menuitem = gtk_menu_item_new_with_label (_("Save to"));
  3563.   g_editor->control_right_save_popup =
  3564.     cpopup_create_save_menu (g_editor->right_save_color_boxes,
  3565.                  g_editor->right_save_labels,
  3566.                  (GtkSignalFunc) cpopup_save_right_callback);
  3567.   gtk_menu_item_set_submenu (GTK_MENU_ITEM(menuitem),
  3568.                  g_editor->control_right_save_popup);
  3569.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3570.   gtk_widget_show (menuitem);
  3571.  
  3572.   /* Blending function */
  3573.   menuitem = gtk_menu_item_new ();
  3574.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3575.   gtk_widget_show (menuitem);
  3576.  
  3577.   menuitem = cpopup_create_menu_item_with_label ("", &g_editor->control_blending_label);
  3578.   g_editor->control_blending_popup = cpopup_create_blending_menu ();
  3579.   gtk_menu_item_set_submenu (GTK_MENU_ITEM(menuitem),
  3580.                  g_editor->control_blending_popup);
  3581.   gtk_menu_append (GTK_MENU(menu), menuitem);
  3582.   gtk_widget_show (menuitem);
  3583.  
  3584.   /* Coloring type */
  3585.   menuitem = cpopup_create_menu_item_with_label ("", &g_editor->control_coloring_label);
  3586.   g_editor->control_coloring_popup = cpopup_create_coloring_menu ();
  3587.   gtk_menu_item_set_submenu (GTK_MENU_ITEM(menuitem),
  3588.                  g_editor->control_coloring_popup);
  3589.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3590.   gtk_widget_show (menuitem);
  3591.  
  3592.   /* Operations */
  3593.   menuitem = gtk_menu_item_new ();
  3594.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3595.   gtk_widget_show (menuitem);
  3596.  
  3597.   /* Split at midpoint */
  3598.   menuitem = cpopup_create_menu_item_with_label ("", &g_editor->control_split_m_label);
  3599.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  3600.               (GtkSignalFunc) cpopup_split_midpoint_callback,
  3601.               NULL);
  3602.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3603.   gtk_widget_show (menuitem);
  3604.   gtk_widget_add_accelerator(menuitem, "activate",
  3605.                  accel_group,
  3606.                  'S', 0,
  3607.                  GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  3608.  
  3609.   /* Split uniformly */
  3610.   menuitem = cpopup_create_menu_item_with_label ("", &g_editor->control_split_u_label);
  3611.   gtk_signal_connect (GTK_OBJECT(menuitem), "activate",
  3612.               (GtkSignalFunc) cpopup_split_uniform_callback,
  3613.               NULL);
  3614.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3615.   gtk_widget_show (menuitem);
  3616.   gtk_widget_add_accelerator (menuitem, "activate",
  3617.                   accel_group,
  3618.                   'U', 0,
  3619.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  3620.  
  3621.   /* Delete */
  3622.   menuitem = cpopup_create_menu_item_with_label ("", &g_editor->control_delete_label);
  3623.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  3624.               (GtkSignalFunc) cpopup_delete_callback,
  3625.               NULL);
  3626.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3627.   gtk_widget_show (menuitem);
  3628.   g_editor->control_delete_menu_item = menuitem;
  3629.   gtk_widget_add_accelerator (menuitem, "activate",
  3630.                   accel_group,
  3631.                   'D', 0,
  3632.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  3633.  
  3634.   /* Recenter */
  3635.   menuitem = cpopup_create_menu_item_with_label ("", &g_editor->control_recenter_label);
  3636.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  3637.               (GtkSignalFunc) cpopup_recenter_callback,
  3638.               NULL);
  3639.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3640.   gtk_widget_show (menuitem);
  3641.   gtk_widget_add_accelerator (menuitem, "activate",
  3642.                   accel_group,
  3643.                   'C', 0,
  3644.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  3645.  
  3646.   /* Redistribute */
  3647.   menuitem = cpopup_create_menu_item_with_label ("", &g_editor->control_redistribute_label);
  3648.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  3649.               (GtkSignalFunc) cpopup_redistribute_callback,
  3650.               NULL);
  3651.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3652.   gtk_widget_show (menuitem);
  3653.   gtk_widget_add_accelerator (menuitem, "activate",
  3654.                   accel_group,
  3655.                   'C', GDK_CONTROL_MASK,
  3656.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  3657.  
  3658.   /* Selection ops */
  3659.   menuitem = gtk_menu_item_new ();
  3660.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3661.   gtk_widget_show (menuitem);
  3662.  
  3663.   menuitem = gtk_menu_item_new_with_label (_("Selection operations"));
  3664.   g_editor->control_sel_ops_popup = cpopup_create_sel_ops_menu ();
  3665.   gtk_menu_item_set_submenu (GTK_MENU_ITEM (menuitem),
  3666.                  g_editor->control_sel_ops_popup);
  3667.   gtk_menu_append (GTK_MENU (menu), menuitem);
  3668.   gtk_widget_show (menuitem);
  3669.  
  3670.   /* Done */
  3671.   g_editor->control_main_popup = menu;
  3672. }
  3673.  
  3674. static void
  3675. cpopup_do_popup (void)
  3676. {
  3677.   cpopup_adjust_menus ();
  3678.   gtk_menu_popup (GTK_MENU (g_editor->control_main_popup),
  3679.           NULL, NULL, NULL, NULL, 3, 0);
  3680. }
  3681.  
  3682. /***** Create a single menu item *****/
  3683.  
  3684. static GtkWidget *
  3685. cpopup_create_color_item (GtkWidget **color_box,
  3686.               GtkWidget **label)
  3687. {
  3688.   GtkWidget *menuitem;
  3689.   GtkWidget *hbox;
  3690.   GtkWidget *vbox;
  3691.   GtkWidget *wcolor_box;
  3692.   GtkWidget *wlabel;
  3693.  
  3694.   menuitem = gtk_menu_item_new();
  3695.  
  3696.   hbox = gtk_hbox_new (FALSE, 0);
  3697.   gtk_container_add (GTK_CONTAINER (menuitem), hbox);
  3698.   gtk_widget_show (hbox);
  3699.  
  3700.   vbox = gtk_vbox_new (FALSE, 0);
  3701.   gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
  3702.   gtk_widget_show (vbox);
  3703.  
  3704.   wcolor_box = gtk_preview_new (GTK_PREVIEW_COLOR);
  3705.   gtk_preview_set_dither (GTK_PREVIEW (wcolor_box), GDK_RGB_DITHER_MAX);
  3706.   gtk_preview_size (GTK_PREVIEW (wcolor_box),
  3707.             GRAD_COLOR_BOX_WIDTH, GRAD_COLOR_BOX_HEIGHT);
  3708.   gtk_box_pack_start (GTK_BOX (vbox), wcolor_box, FALSE, FALSE, 2);
  3709.   gtk_widget_show (wcolor_box);
  3710.  
  3711.   if (color_box)
  3712.     *color_box = wcolor_box;
  3713.  
  3714.   wlabel = gtk_label_new ("");
  3715.   gtk_misc_set_alignment (GTK_MISC (wlabel), 0.0, 0.5);
  3716.   gtk_box_pack_start (GTK_BOX (hbox), wlabel, FALSE, FALSE, 4);
  3717.   gtk_widget_show (wlabel);
  3718.  
  3719.   if (label)
  3720.     *label = wlabel;
  3721.  
  3722.   return menuitem;
  3723. }
  3724.  
  3725. static GtkWidget *
  3726. cpopup_create_menu_item_with_label (gchar      *str,
  3727.                     GtkWidget **label)
  3728. {
  3729.   GtkWidget *menuitem;
  3730.   GtkWidget *accel_label;
  3731.  
  3732.   menuitem = gtk_menu_item_new ();
  3733.  
  3734.   accel_label = gtk_accel_label_new (str);
  3735.   gtk_misc_set_alignment (GTK_MISC (accel_label), 0.0, 0.5);
  3736.   gtk_container_add (GTK_CONTAINER (menuitem), accel_label);
  3737.   gtk_accel_label_set_accel_widget (GTK_ACCEL_LABEL (accel_label), menuitem);
  3738.   gtk_widget_show (accel_label);
  3739.  
  3740.   if (label)
  3741.     *label = accel_label;
  3742.  
  3743.   return menuitem;
  3744. }
  3745.  
  3746. /***** Update all menus *****/
  3747.  
  3748. static void
  3749. cpopup_adjust_menus (void)
  3750. {
  3751.   grad_segment_t *seg;
  3752.   gint            i;
  3753.   gdouble         fg_r, fg_g, fg_b;
  3754.   gdouble         fg_a;
  3755.  
  3756.   /* Render main menu color boxes */
  3757.   cpopup_render_color_box (GTK_PREVIEW (g_editor->left_color_preview),
  3758.                g_editor->control_sel_l->r0,
  3759.                g_editor->control_sel_l->g0,
  3760.                g_editor->control_sel_l->b0,
  3761.                g_editor->control_sel_l->a0);
  3762.  
  3763.   cpopup_render_color_box (GTK_PREVIEW (g_editor->right_color_preview),
  3764.                g_editor->control_sel_r->r1,
  3765.                g_editor->control_sel_r->g1,
  3766.                g_editor->control_sel_r->b1,
  3767.                g_editor->control_sel_r->a1);
  3768.  
  3769.   /* Render load color from endpoint color boxes */
  3770.  
  3771.   if (g_editor->control_sel_l->prev != NULL)
  3772.     seg = g_editor->control_sel_l->prev;
  3773.   else
  3774.     seg = seg_get_last_segment (g_editor->control_sel_l);
  3775.  
  3776.   cpopup_render_color_box (GTK_PREVIEW (g_editor->left_load_color_boxes[0]),
  3777.                seg->r1,
  3778.                seg->g1,
  3779.                seg->b1,
  3780.                seg->a1);
  3781.  
  3782.   cpopup_render_color_box (GTK_PREVIEW (g_editor->left_load_color_boxes[1]),
  3783.                g_editor->control_sel_r->r1,
  3784.                g_editor->control_sel_r->g1,
  3785.                g_editor->control_sel_r->b1,
  3786.                g_editor->control_sel_r->a1);
  3787.  
  3788.   if (g_editor->control_sel_r->next != NULL)
  3789.     seg = g_editor->control_sel_r->next;
  3790.   else
  3791.     seg = curr_gradient->segments;
  3792.  
  3793.   cpopup_render_color_box (GTK_PREVIEW (g_editor->right_load_color_boxes[0]),
  3794.                seg->r0,
  3795.                seg->g0,
  3796.                seg->b0,
  3797.                seg->a0);
  3798.  
  3799.   cpopup_render_color_box (GTK_PREVIEW (g_editor->right_load_color_boxes[1]),
  3800.                g_editor->control_sel_l->r0,
  3801.                g_editor->control_sel_l->g0,
  3802.                g_editor->control_sel_l->b0,
  3803.                g_editor->control_sel_l->a0);
  3804.  
  3805.   /* Render Foreground color boxes */
  3806.  
  3807.   ed_fetch_foreground (&fg_r, &fg_g, &fg_b, &fg_a);
  3808.  
  3809.   cpopup_render_color_box (GTK_PREVIEW (g_editor->left_load_color_boxes[2]),
  3810.                fg_r,
  3811.                fg_g,
  3812.                fg_b,
  3813.                fg_a);
  3814.  
  3815.   cpopup_render_color_box (GTK_PREVIEW (g_editor->right_load_color_boxes[2]),
  3816.                fg_r,
  3817.                fg_g,
  3818.                fg_b,
  3819.                fg_a);
  3820.     
  3821.   /* Render saved color boxes */
  3822.  
  3823.   for (i = 0; i < GRAD_NUM_COLORS; i++)
  3824.     cpopup_update_saved_color (i,
  3825.                    g_editor->saved_colors[i].r,
  3826.                    g_editor->saved_colors[i].g,
  3827.                    g_editor->saved_colors[i].b,
  3828.                    g_editor->saved_colors[i].a);
  3829.  
  3830.   /* Adjust labels */
  3831.  
  3832.   if (g_editor->control_sel_l == g_editor->control_sel_r)
  3833.     {
  3834.       gtk_label_set_text (GTK_LABEL (g_editor->control_blending_label),
  3835.               _("Blending function for segment"));
  3836.       gtk_label_set_text (GTK_LABEL (g_editor->control_coloring_label),
  3837.               _("Coloring type for segment"));
  3838.       gtk_label_set_text (GTK_LABEL (g_editor->control_split_m_label),
  3839.               _("Split segment at midpoint"));
  3840.       gtk_label_set_text (GTK_LABEL (g_editor->control_split_u_label),
  3841.               _("Split segment uniformly"));
  3842.       gtk_label_set_text (GTK_LABEL (g_editor->control_delete_label),
  3843.               _("Delete segment"));
  3844.       gtk_label_set_text (GTK_LABEL (g_editor->control_recenter_label),
  3845.               _("Re-center segment's midpoint"));
  3846.       gtk_label_set_text (GTK_LABEL (g_editor->control_redistribute_label),
  3847.               _("Re-distribute handles in segment"));
  3848.       gtk_label_set_text (GTK_LABEL (g_editor->control_flip_label),
  3849.               _("Flip segment"));
  3850.       gtk_label_set_text (GTK_LABEL (g_editor->control_replicate_label),
  3851.               _("Replicate segment"));
  3852.     }
  3853.   else
  3854.     {
  3855.       gtk_label_set_text (GTK_LABEL (g_editor->control_blending_label),
  3856.               _("Blending function for selection"));
  3857.       gtk_label_set_text (GTK_LABEL (g_editor->control_coloring_label),
  3858.               _("Coloring type for selection"));
  3859.       gtk_label_set_text (GTK_LABEL (g_editor->control_split_m_label),
  3860.               _("Split segments at midpoints"));
  3861.       gtk_label_set_text (GTK_LABEL (g_editor->control_split_u_label),
  3862.               _("Split segments uniformly"));
  3863.       gtk_label_set_text (GTK_LABEL (g_editor->control_delete_label),
  3864.               _("Delete selection"));
  3865.       gtk_label_set_text (GTK_LABEL (g_editor->control_recenter_label),
  3866.               _("Re-center midpoints in selection"));
  3867.       gtk_label_set_text (GTK_LABEL (g_editor->control_redistribute_label),
  3868.               _("Re-distribute handles in selection"));
  3869.       gtk_label_set_text (GTK_LABEL (g_editor->control_flip_label),
  3870.               _("Flip selection"));
  3871.       gtk_label_set_text (GTK_LABEL (g_editor->control_replicate_label),
  3872.               _("Replicate selection"));
  3873.     }
  3874.  
  3875.   /* Adjust blending and coloring menus */
  3876.   cpopup_adjust_blending_menu ();
  3877.   cpopup_adjust_coloring_menu ();
  3878.  
  3879.   /* Can invoke delete? */
  3880.   if ((g_editor->control_sel_l->prev == NULL) &&
  3881.       (g_editor->control_sel_r->next == NULL))
  3882.     gtk_widget_set_sensitive (g_editor->control_delete_menu_item, FALSE);
  3883.   else
  3884.     gtk_widget_set_sensitive (g_editor->control_delete_menu_item, TRUE);
  3885.  
  3886.   /* Can invoke blend colors / opacity? */
  3887.   if (g_editor->control_sel_l == g_editor->control_sel_r)
  3888.     {
  3889.       gtk_widget_set_sensitive (g_editor->control_blend_colors_menu_item, FALSE);
  3890.       gtk_widget_set_sensitive (g_editor->control_blend_opacity_menu_item, FALSE);
  3891.     }
  3892.   else
  3893.     {
  3894.       gtk_widget_set_sensitive (g_editor->control_blend_colors_menu_item, TRUE);
  3895.       gtk_widget_set_sensitive (g_editor->control_blend_opacity_menu_item, TRUE);
  3896.     }
  3897. }
  3898.  
  3899. static void
  3900. cpopup_adjust_blending_menu (void)
  3901. {
  3902.   gint  equal;
  3903.   glong i, num_items;
  3904.   gint  type;
  3905.  
  3906.   cpopup_check_selection_params (&equal, NULL);
  3907.  
  3908.   /* Block activate signals */
  3909.   num_items = (sizeof (g_editor->control_blending_items) /
  3910.            sizeof (g_editor->control_blending_items[0]));
  3911.  
  3912.   type = (int) g_editor->control_sel_l->type;
  3913.  
  3914.   for (i = 0; i < num_items; i++)
  3915.     gtk_signal_handler_block_by_data
  3916.       (GTK_OBJECT (g_editor->control_blending_items[i]), (gpointer) i);
  3917.  
  3918.   /* Set state */
  3919.   if (equal)
  3920.     {
  3921.       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (g_editor->control_blending_items[type]), TRUE);
  3922.       gtk_widget_hide (g_editor->control_blending_items[num_items - 1]);
  3923.     }
  3924.   else
  3925.     {
  3926.       gtk_widget_show (g_editor->control_blending_items[num_items - 1]);
  3927.       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (g_editor->control_blending_items[num_items - 1]), TRUE);
  3928.     }
  3929.  
  3930.   /* Unblock signals */
  3931.   for (i = 0; i < num_items; i++)
  3932.     gtk_signal_handler_unblock_by_data (GTK_OBJECT (g_editor->control_blending_items[i]), (gpointer) i);
  3933. }
  3934.  
  3935. static void
  3936. cpopup_adjust_coloring_menu (void)
  3937. {
  3938.   gint  equal;
  3939.   glong i, num_items;
  3940.   gint  coloring;
  3941.  
  3942.   cpopup_check_selection_params (NULL, &equal);
  3943.  
  3944.   /* Block activate signals */
  3945.   num_items = (sizeof (g_editor->control_coloring_items) /
  3946.            sizeof (g_editor->control_coloring_items[0]));
  3947.  
  3948.   coloring = (int) g_editor->control_sel_l->color;
  3949.  
  3950.   for (i = 0; i < num_items; i++)
  3951.     gtk_signal_handler_block_by_data (GTK_OBJECT (g_editor->control_coloring_items[i]), (gpointer) i);
  3952.  
  3953.   /* Set state */
  3954.   if (equal)
  3955.     {
  3956.       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (g_editor->control_coloring_items[coloring]), TRUE);
  3957.       gtk_widget_hide (g_editor->control_coloring_items[num_items - 1]);
  3958.     }
  3959.   else
  3960.     {
  3961.       gtk_widget_show (g_editor->control_coloring_items[num_items - 1]);
  3962.       gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (g_editor->control_coloring_items[num_items - 1]), TRUE);
  3963.     }
  3964.  
  3965.   /* Unblock signals */
  3966.   for (i = 0; i < num_items; i++)
  3967.     gtk_signal_handler_unblock_by_data (GTK_OBJECT (g_editor->control_coloring_items[i]), (gpointer) i);
  3968. }
  3969.  
  3970. static void
  3971. cpopup_check_selection_params (gint *equal_blending,
  3972.                    gint *equal_coloring)
  3973. {
  3974.   grad_type_t     type;
  3975.   grad_color_t    color;
  3976.   int             etype, ecolor;
  3977.   grad_segment_t *seg, *aseg;
  3978.  
  3979.   type  = g_editor->control_sel_l->type;
  3980.   color = g_editor->control_sel_l->color;
  3981.  
  3982.   etype  = 1;
  3983.   ecolor = 1;
  3984.  
  3985.   seg = g_editor->control_sel_l;
  3986.  
  3987.   do
  3988.     {
  3989.       etype  = etype && (seg->type == type);
  3990.       ecolor = ecolor && (seg->color == color);
  3991.  
  3992.       aseg = seg;
  3993.       seg  = seg->next;
  3994.     }
  3995.   while (aseg != g_editor->control_sel_r);
  3996.  
  3997.   if (equal_blending)
  3998.     *equal_blending = etype;
  3999.  
  4000.   if (equal_coloring)
  4001.     *equal_coloring = ecolor;
  4002. }
  4003.  
  4004. /*****/
  4005.  
  4006. static void
  4007. cpopup_render_color_box (GtkPreview *preview,
  4008.              double      r,
  4009.              double      g,
  4010.              double      b,
  4011.              double      a)
  4012. {
  4013.   guchar  rows[3][GRAD_COLOR_BOX_WIDTH * 3];
  4014.   int     x, y;
  4015.   int     r0, g0, b0;
  4016.   int     r1, g1, b1;
  4017.   guchar *p0, *p1, *p2;
  4018.  
  4019.   /* Fill rows */
  4020.  
  4021.   r0 = (GIMP_CHECK_DARK + (r - GIMP_CHECK_DARK) * a) * 255.0;
  4022.   r1 = (GIMP_CHECK_LIGHT + (r - GIMP_CHECK_LIGHT) * a) * 255.0;
  4023.  
  4024.   g0 = (GIMP_CHECK_DARK + (g - GIMP_CHECK_DARK) * a) * 255.0;
  4025.   g1 = (GIMP_CHECK_LIGHT + (g - GIMP_CHECK_LIGHT) * a) * 255.0;
  4026.  
  4027.   b0 = (GIMP_CHECK_DARK + (b - GIMP_CHECK_DARK) * a) * 255.0;
  4028.   b1 = (GIMP_CHECK_LIGHT + (b - GIMP_CHECK_LIGHT) * a) * 255.0;
  4029.  
  4030.   p0 = rows[0];
  4031.   p1 = rows[1];
  4032.   p2 = rows[2];
  4033.  
  4034.   for (x = 0; x < GRAD_COLOR_BOX_WIDTH; x++)
  4035.     {
  4036.       if ((x == 0) || (x == (GRAD_COLOR_BOX_WIDTH - 1)))
  4037.     {
  4038.       *p0++ = 0;
  4039.       *p0++ = 0;
  4040.       *p0++ = 0;
  4041.  
  4042.       *p1++ = 0;
  4043.       *p1++ = 0;
  4044.       *p1++ = 0;
  4045.     }
  4046.       else
  4047.     if ((x / GIMP_CHECK_SIZE) & 1)
  4048.       {
  4049.         *p0++ = r1;
  4050.         *p0++ = g1;
  4051.         *p0++ = b1;
  4052.  
  4053.         *p1++ = r0;
  4054.         *p1++ = g0;
  4055.         *p1++ = b0;
  4056.       }
  4057.     else
  4058.       {
  4059.         *p0++ = r0;
  4060.         *p0++ = g0;
  4061.         *p0++ = b0;
  4062.  
  4063.         *p1++ = r1;
  4064.         *p1++ = g1;
  4065.         *p1++ = b1;
  4066.       }
  4067.  
  4068.       *p2++ = 0;
  4069.       *p2++ = 0;
  4070.       *p2++ = 0;
  4071.     }
  4072.  
  4073.   /* Fill preview */
  4074.  
  4075.   gtk_preview_draw_row (preview, rows[2], 0, 0, GRAD_COLOR_BOX_WIDTH);
  4076.  
  4077.   for (y = 1; y < (GRAD_COLOR_BOX_HEIGHT - 1); y++)
  4078.     if ((y / GIMP_CHECK_SIZE) & 1)
  4079.       gtk_preview_draw_row (preview, rows[1], 0, y, GRAD_COLOR_BOX_WIDTH);
  4080.     else
  4081.       gtk_preview_draw_row (preview, rows[0], 0, y, GRAD_COLOR_BOX_WIDTH);
  4082.  
  4083.   gtk_preview_draw_row (preview, rows[2], 0, y, GRAD_COLOR_BOX_WIDTH);
  4084. }
  4085.  
  4086. /***** Creale load & save menus *****/
  4087.  
  4088. static GtkWidget *
  4089. cpopup_create_load_menu (GtkWidget    **color_boxes,
  4090.              GtkWidget    **labels,
  4091.              gchar         *label1,
  4092.              gchar         *label2,
  4093.              GtkSignalFunc  callback,
  4094.              gchar accel_key_0, guint8 accel_mods_0,
  4095.              gchar accel_key_1, guint8 accel_mods_1,
  4096.              gchar accel_key_2, guint8 accel_mods_2)
  4097. {
  4098.   GtkWidget     *menu;
  4099.   GtkWidget     *menuitem;
  4100.   GtkAccelGroup *accel_group;
  4101.   gint i;
  4102.  
  4103.   menu = gtk_menu_new ();
  4104.   accel_group = g_editor->accel_group;
  4105.  
  4106.   gtk_menu_set_accel_group (GTK_MENU (menu), accel_group);
  4107.  
  4108.   /* Create items */
  4109.   for (i = 0; i < (GRAD_NUM_COLORS + 3); i++)
  4110.     {
  4111.       if (i == 3)
  4112.     {
  4113.       /* Insert separator between "to fetch" and "saved" colors */
  4114.       menuitem = gtk_menu_item_new ();
  4115.       gtk_menu_append (GTK_MENU (menu), menuitem);
  4116.       gtk_widget_show (menuitem);
  4117.     }
  4118.  
  4119.       menuitem = cpopup_create_color_item (&color_boxes[i], &labels[i]);
  4120.       gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  4121.               callback, (gpointer) ((long) i));
  4122.       gtk_menu_append (GTK_MENU (menu), menuitem);
  4123.       gtk_widget_show (menuitem);
  4124.  
  4125.       switch (i)
  4126.     {
  4127.     case 0:
  4128.       gtk_widget_add_accelerator (menuitem, "activate",
  4129.                       accel_group,
  4130.                       accel_key_0, accel_mods_0,
  4131.                       GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  4132.       break;
  4133.           
  4134.     case 1:
  4135.       gtk_widget_add_accelerator (menuitem, "activate",
  4136.                       accel_group,
  4137.                       accel_key_1, accel_mods_1,
  4138.                       GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  4139.       break;
  4140.           
  4141.     case 2:
  4142.       gtk_widget_add_accelerator (menuitem, "activate",
  4143.                       accel_group,
  4144.                       accel_key_2, accel_mods_2,
  4145.                       GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  4146.       break;
  4147.           
  4148.     default:
  4149.       break;
  4150.     }
  4151.     }
  4152.  
  4153.   /* Set labels */
  4154.   gtk_label_set_text (GTK_LABEL (labels[0]), label1);
  4155.   gtk_label_set_text (GTK_LABEL (labels[1]), label2);
  4156.   gtk_label_set_text (GTK_LABEL (labels[2]), _("FG color"));
  4157.  
  4158.   return menu;
  4159. }
  4160.  
  4161. static GtkWidget *
  4162. cpopup_create_save_menu (GtkWidget     **color_boxes,
  4163.              GtkWidget     **labels,
  4164.              GtkSignalFunc   callback)
  4165. {
  4166.   GtkWidget *menu;
  4167.   GtkWidget *menuitem;
  4168.   gint i;
  4169.  
  4170.   menu = gtk_menu_new ();
  4171.  
  4172.   for (i = 0; i < GRAD_NUM_COLORS; i++)
  4173.     {
  4174.       menuitem = cpopup_create_color_item (&color_boxes[i], &labels[i]);
  4175.       gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  4176.               callback, (gpointer) ((long) i));
  4177.       gtk_menu_append (GTK_MENU (menu), menuitem);
  4178.       gtk_widget_show (menuitem);
  4179.     }
  4180.  
  4181.   return menu;
  4182. }
  4183.  
  4184. /*****/
  4185.  
  4186. static void
  4187. cpopup_update_saved_color (int    n,
  4188.                double r,
  4189.                double g,
  4190.                double b,
  4191.                double a)
  4192. {
  4193.   gchar *str;
  4194.  
  4195.   cpopup_render_color_box (GTK_PREVIEW (g_editor->left_load_color_boxes[n + 3]),
  4196.                r, g, b, a);
  4197.   cpopup_render_color_box (GTK_PREVIEW (g_editor->left_save_color_boxes[n]),
  4198.                r, g, b, a);
  4199.   cpopup_render_color_box (GTK_PREVIEW (g_editor->right_load_color_boxes[n + 3]),
  4200.                r, g, b, a);
  4201.   cpopup_render_color_box (GTK_PREVIEW (g_editor->right_save_color_boxes[n]),
  4202.                r, g, b, a);
  4203.  
  4204.   str = g_strdup_printf (_("RGBA (%0.3f, %0.3f, %0.3f, %0.3f)"), r, g, b, a);
  4205.  
  4206.   gtk_label_set_text (GTK_LABEL (g_editor->left_load_labels[n + 3]), str);
  4207.   gtk_label_set_text (GTK_LABEL (g_editor->left_save_labels[n]), str);
  4208.   gtk_label_set_text (GTK_LABEL (g_editor->right_load_labels[n + 3]), str);
  4209.   gtk_label_set_text (GTK_LABEL (g_editor->right_save_labels[n]), str);
  4210.  
  4211.   g_free (str);
  4212.  
  4213.   g_editor->saved_colors[n].r = r;
  4214.   g_editor->saved_colors[n].g = g;
  4215.   g_editor->saved_colors[n].b = b;
  4216.   g_editor->saved_colors[n].a = a;
  4217. }
  4218.  
  4219. /*****/
  4220.  
  4221. static void
  4222. cpopup_load_left_callback (GtkWidget *widget,
  4223.                gpointer   data)
  4224. {
  4225.   grad_segment_t *seg;
  4226.   double          fg_r, fg_g, fg_b;
  4227.   double          fg_a;
  4228.  
  4229.   switch ((long) data)
  4230.     {
  4231.     case 0: /* Fetch from left neighbor's right endpoint */
  4232.       if (g_editor->control_sel_l->prev != NULL)
  4233.     seg = g_editor->control_sel_l->prev;
  4234.       else
  4235.     seg = seg_get_last_segment (g_editor->control_sel_l);
  4236.  
  4237.       cpopup_blend_endpoints (seg->r1, seg->g1, seg->b1, seg->a1,
  4238.                   g_editor->control_sel_r->r1,
  4239.                   g_editor->control_sel_r->g1,
  4240.                   g_editor->control_sel_r->b1,
  4241.                   g_editor->control_sel_r->a1,
  4242.                   TRUE, TRUE);
  4243.       break;
  4244.  
  4245.     case 1: /* Fetch from right endpoint */
  4246.       cpopup_blend_endpoints (g_editor->control_sel_r->r1,
  4247.                   g_editor->control_sel_r->g1,
  4248.                   g_editor->control_sel_r->b1,
  4249.                   g_editor->control_sel_r->a1,
  4250.                   g_editor->control_sel_r->r1,
  4251.                   g_editor->control_sel_r->g1,
  4252.                   g_editor->control_sel_r->b1,
  4253.                   g_editor->control_sel_r->a1,
  4254.                   TRUE, TRUE);
  4255.       break;
  4256.  
  4257.     case 2: /* Fetch from FG color */
  4258.       ed_fetch_foreground (&fg_r, &fg_g, &fg_b, &fg_a);
  4259.       cpopup_blend_endpoints (fg_r,
  4260.                   fg_g,
  4261.                   fg_b,
  4262.                   fg_a,
  4263.                   g_editor->control_sel_r->r1,
  4264.                   g_editor->control_sel_r->g1,
  4265.                   g_editor->control_sel_r->b1,
  4266.                   g_editor->control_sel_r->a1,
  4267.                   TRUE, TRUE);
  4268.       break;
  4269.  
  4270.     default: /* Load a color */
  4271.       cpopup_blend_endpoints (g_editor->saved_colors[(long) data - 3].r,
  4272.                   g_editor->saved_colors[(long) data - 3].g,
  4273.                   g_editor->saved_colors[(long) data - 3].b,
  4274.                   g_editor->saved_colors[(long) data - 3].a,
  4275.                   g_editor->control_sel_r->r1,
  4276.                   g_editor->control_sel_r->g1,
  4277.                   g_editor->control_sel_r->b1,
  4278.                   g_editor->control_sel_r->a1,
  4279.                   TRUE, TRUE);
  4280.       break;
  4281.     }
  4282.  
  4283.   curr_gradient->dirty = TRUE;
  4284.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  4285. }
  4286.  
  4287. static void
  4288. cpopup_save_left_callback (GtkWidget *widget,
  4289.                gpointer   data)
  4290. {
  4291.   g_editor->saved_colors[(long) data].r = g_editor->control_sel_l->r0;
  4292.   g_editor->saved_colors[(long) data].g = g_editor->control_sel_l->g0;
  4293.   g_editor->saved_colors[(long) data].b = g_editor->control_sel_l->b0;
  4294.   g_editor->saved_colors[(long) data].a = g_editor->control_sel_l->a0;
  4295. }
  4296.  
  4297. static void
  4298. cpopup_load_right_callback (GtkWidget *widget,
  4299.                 gpointer   data)
  4300. {
  4301.   grad_segment_t *seg;
  4302.   double          fg_r, fg_g, fg_b;
  4303.   double          fg_a;
  4304.  
  4305.   switch ((long) data)
  4306.     {
  4307.     case 0: /* Fetch from right neighbor's left endpoint */
  4308.       if (g_editor->control_sel_r->next != NULL)
  4309.     seg = g_editor->control_sel_r->next;
  4310.       else
  4311.     seg = curr_gradient->segments;
  4312.  
  4313.       cpopup_blend_endpoints (g_editor->control_sel_r->r0,
  4314.                   g_editor->control_sel_r->g0,
  4315.                   g_editor->control_sel_r->b0,
  4316.                   g_editor->control_sel_r->a0,
  4317.                   seg->r0, seg->g0, seg->b0, seg->a0,
  4318.                   TRUE, TRUE);
  4319.       break;
  4320.  
  4321.     case 1: /* Fetch from left endpoint */
  4322.       cpopup_blend_endpoints (g_editor->control_sel_l->r0,
  4323.                   g_editor->control_sel_l->g0,
  4324.                   g_editor->control_sel_l->b0,
  4325.                   g_editor->control_sel_l->a0,
  4326.                   g_editor->control_sel_l->r0,
  4327.                   g_editor->control_sel_l->g0,
  4328.                   g_editor->control_sel_l->b0,
  4329.                   g_editor->control_sel_l->a0,
  4330.                   TRUE, TRUE);
  4331.       break;
  4332.  
  4333.     case 2: /* Fetch from FG color */
  4334.       ed_fetch_foreground (&fg_r, &fg_g, &fg_b, &fg_a);
  4335.       cpopup_blend_endpoints (g_editor->control_sel_l->r0,
  4336.                   g_editor->control_sel_l->g0,
  4337.                   g_editor->control_sel_l->b0,
  4338.                   g_editor->control_sel_l->a0,
  4339.                   fg_r,
  4340.                   fg_g,
  4341.                   fg_b,
  4342.                   fg_a,
  4343.                   TRUE, TRUE);
  4344.       break;
  4345.  
  4346.     default: /* Load a color */
  4347.       cpopup_blend_endpoints (g_editor->control_sel_l->r0,
  4348.                   g_editor->control_sel_l->g0,
  4349.                   g_editor->control_sel_l->b0,
  4350.                   g_editor->control_sel_l->a0,
  4351.                   g_editor->saved_colors[(long) data - 3].r,
  4352.                   g_editor->saved_colors[(long) data - 3].g,
  4353.                   g_editor->saved_colors[(long) data - 3].b,
  4354.                   g_editor->saved_colors[(long) data - 3].a,
  4355.                   TRUE, TRUE);
  4356.       break;
  4357.     }
  4358.  
  4359.   curr_gradient->dirty = TRUE;
  4360.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  4361. }
  4362.  
  4363. static void
  4364. cpopup_save_right_callback (GtkWidget *widget,
  4365.                 gpointer   data)
  4366. {
  4367.   g_editor->saved_colors[(long) data].r = g_editor->control_sel_r->r1;
  4368.   g_editor->saved_colors[(long) data].g = g_editor->control_sel_r->g1;
  4369.   g_editor->saved_colors[(long) data].b = g_editor->control_sel_r->b1;
  4370.   g_editor->saved_colors[(long) data].a = g_editor->control_sel_r->a1;
  4371. }
  4372.  
  4373. /*****/
  4374.  
  4375. static void
  4376. cpopup_set_color_selection_color (GtkColorSelection *cs,
  4377.                   double             r,
  4378.                   double             g,
  4379.                   double             b,
  4380.                   double             a)
  4381. {
  4382.   gdouble color[4];
  4383.  
  4384.   color[0] = r;
  4385.   color[1] = g;
  4386.   color[2] = b;
  4387.   color[3] = a;
  4388.  
  4389.   gtk_color_selection_set_color (cs, color);
  4390. }
  4391.  
  4392. static void
  4393. cpopup_get_color_selection_color (GtkColorSelection *cs,
  4394.                   double            *r,
  4395.                   double            *g,
  4396.                   double            *b,
  4397.                   double            *a)
  4398. {
  4399.   gdouble color[4];
  4400.  
  4401.   gtk_color_selection_get_color (cs, color);
  4402.  
  4403.   *r = color[0];
  4404.   *g = color[1];
  4405.   *b = color[2];
  4406.   *a = color[3];
  4407. }
  4408.  
  4409. /*****/
  4410.  
  4411. static grad_segment_t *
  4412. cpopup_save_selection (void)
  4413. {
  4414.   grad_segment_t *seg, *prev, *tmp;
  4415.   grad_segment_t *oseg, *oaseg;
  4416.  
  4417.   prev = NULL;
  4418.   oseg = g_editor->control_sel_l;
  4419.   tmp  = NULL;
  4420.  
  4421.   do
  4422.     {
  4423.       seg = seg_new_segment ();
  4424.  
  4425.       *seg = *oseg; /* Copy everything */
  4426.  
  4427.       if (prev == NULL)
  4428.     tmp = seg; /* Remember first segment */
  4429.       else
  4430.     prev->next = seg;
  4431.  
  4432.       seg->prev = prev;
  4433.       seg->next = NULL;
  4434.  
  4435.       prev  = seg;
  4436.       oaseg = oseg;
  4437.       oseg  = oseg->next;
  4438.     }
  4439.   while (oaseg != g_editor->control_sel_r);
  4440.  
  4441.   return tmp;
  4442. }
  4443.  
  4444. /*****/
  4445.  
  4446. static void
  4447. cpopup_free_selection (grad_segment_t *seg)
  4448. {
  4449.   seg_free_segments (seg);
  4450. }
  4451.  
  4452. /*****/
  4453.  
  4454. static void
  4455. cpopup_replace_selection (grad_segment_t *replace_seg)
  4456. {
  4457.   grad_segment_t *lseg, *rseg;
  4458.   grad_segment_t *replace_last;
  4459.  
  4460.   /* Remember left and right segments */
  4461.  
  4462.   lseg = g_editor->control_sel_l->prev;
  4463.   rseg = g_editor->control_sel_r->next;
  4464.  
  4465.   replace_last = seg_get_last_segment (replace_seg);
  4466.  
  4467.   /* Free old selection */
  4468.  
  4469.   g_editor->control_sel_r->next = NULL;
  4470.  
  4471.   seg_free_segments (g_editor->control_sel_l);
  4472.  
  4473.   /* Link in new segments */
  4474.  
  4475.   if (lseg)
  4476.     lseg->next = replace_seg;
  4477.   else
  4478.     curr_gradient->segments = replace_seg;
  4479.  
  4480.   replace_seg->prev = lseg;
  4481.  
  4482.   if (rseg)
  4483.     rseg->prev = replace_last;
  4484.  
  4485.   replace_last->next = rseg;
  4486.  
  4487.   g_editor->control_sel_l = replace_seg;
  4488.   g_editor->control_sel_r = replace_last;
  4489.  
  4490.   curr_gradient->last_visited = NULL; /* Force re-search */
  4491. }
  4492.  
  4493. /***** Color dialogs for left and right endpoint *****/
  4494.  
  4495. static void
  4496. cpopup_create_color_dialog (gchar         *title,
  4497.                 double         r,
  4498.                 double         g,
  4499.                 double         b,
  4500.                 double         a,
  4501.                 GtkSignalFunc  color_changed_callback,
  4502.                 GtkSignalFunc  ok_callback,
  4503.                 GtkSignalFunc  cancel_callback,
  4504.                 GtkSignalFunc  delete_callback)
  4505. {
  4506.   GtkWidget               *window;
  4507.   GtkColorSelection       *cs;
  4508.   GtkColorSelectionDialog *csd;
  4509.  
  4510.   window = gtk_color_selection_dialog_new (title);
  4511.   gtk_container_set_border_width (GTK_CONTAINER (window), 2);
  4512.   gtk_widget_destroy (GTK_COLOR_SELECTION_DIALOG (window)->help_button);
  4513.  
  4514.   gimp_help_connect_help_accel (window, gimp_standard_help_func,
  4515.                 "dialogs/gradient_editor/gradient_editor.html");
  4516.  
  4517.   csd = GTK_COLOR_SELECTION_DIALOG (window);
  4518.   cs  = GTK_COLOR_SELECTION (csd->colorsel);
  4519.  
  4520.   gtk_color_selection_set_opacity (cs, TRUE);
  4521.   gtk_color_selection_set_update_policy (cs,
  4522.                      g_editor->instant_update ?
  4523.                      GTK_UPDATE_CONTINUOUS :
  4524.                      GTK_UPDATE_DELAYED);
  4525.  
  4526.   /* FIXME: this is a hack; we set the color twice so that the
  4527.    * color selector remembers it as its "old" color, too
  4528.    */
  4529.   cpopup_set_color_selection_color (cs, r, g, b, a);
  4530.   cpopup_set_color_selection_color (cs, r, g, b, a);
  4531.  
  4532.   gtk_signal_connect (GTK_OBJECT (csd), "delete_event",
  4533.              delete_callback, window);
  4534.  
  4535.   gtk_signal_connect (GTK_OBJECT (cs), "color_changed",
  4536.              color_changed_callback, window);
  4537.  
  4538.   gtk_signal_connect (GTK_OBJECT (csd->ok_button), "clicked",
  4539.               ok_callback, window);
  4540.  
  4541.   gtk_signal_connect (GTK_OBJECT (csd->cancel_button), "clicked",
  4542.               cancel_callback, window);
  4543.  
  4544.   gtk_window_set_position (GTK_WINDOW (window), GTK_WIN_POS_MOUSE);
  4545.   gtk_widget_show (window);
  4546. }
  4547.  
  4548. /*****/
  4549.  
  4550. static void
  4551. cpopup_set_left_color_callback (GtkWidget *widget,
  4552.                 gpointer   data)
  4553. {
  4554.   g_editor->left_saved_dirty    = curr_gradient->dirty;
  4555.   g_editor->left_saved_segments = cpopup_save_selection ();
  4556.  
  4557.   cpopup_create_color_dialog (_("Left endpoint's color"),
  4558.                   g_editor->control_sel_l->r0,
  4559.                   g_editor->control_sel_l->g0,
  4560.                   g_editor->control_sel_l->b0,
  4561.                   g_editor->control_sel_l->a0,
  4562.                   (GtkSignalFunc) cpopup_left_color_changed,
  4563.                   (GtkSignalFunc) cpopup_left_color_dialog_ok,
  4564.                   (GtkSignalFunc) cpopup_left_color_dialog_cancel,
  4565.                   (GtkSignalFunc) cpopup_left_color_dialog_delete);
  4566.  
  4567.   gtk_widget_set_sensitive (g_editor->shell, FALSE);
  4568. }
  4569.  
  4570. static void
  4571. cpopup_left_color_changed (GtkWidget *widget,
  4572.                gpointer   data)
  4573. {
  4574.   GtkColorSelection *cs;
  4575.   double             r, g, b, a;
  4576.  
  4577.   cs = GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (data)->colorsel);
  4578.  
  4579.   cpopup_get_color_selection_color (cs, &r, &g, &b, &a);
  4580.  
  4581.   cpopup_blend_endpoints (r, g, b, a,
  4582.               g_editor->control_sel_r->r1,
  4583.               g_editor->control_sel_r->g1,
  4584.               g_editor->control_sel_r->b1,
  4585.               g_editor->control_sel_r->a1,
  4586.               TRUE, TRUE);
  4587.  
  4588.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  4589. }
  4590.  
  4591. static void
  4592. cpopup_left_color_dialog_ok (GtkWidget *widget,
  4593.                  gpointer   data)
  4594. {
  4595.   cpopup_left_color_changed (widget, data);
  4596.  
  4597.   curr_gradient->dirty = TRUE;
  4598.   cpopup_free_selection(g_editor->left_saved_segments);
  4599.  
  4600.   gtk_widget_destroy (GTK_WIDGET (data));
  4601.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  4602. }
  4603.  
  4604. static void
  4605. cpopup_left_color_dialog_cancel (GtkWidget *widget,
  4606.                  gpointer   data)
  4607. {
  4608.   curr_gradient->dirty = g_editor->left_saved_dirty;
  4609.   cpopup_replace_selection (g_editor->left_saved_segments);
  4610.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  4611.  
  4612.   gtk_widget_destroy (GTK_WIDGET (data));
  4613.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  4614. }
  4615.  
  4616. static int
  4617. cpopup_left_color_dialog_delete (GtkWidget *widget,
  4618.                  GdkEvent  *event,
  4619.                  gpointer   data)
  4620. {
  4621.   cpopup_left_color_dialog_cancel (widget, data);
  4622.  
  4623.   return TRUE;
  4624. }
  4625.  
  4626. /*****/
  4627.  
  4628. static void
  4629. cpopup_set_right_color_callback (GtkWidget *widget,
  4630.                  gpointer   data)
  4631. {
  4632.   g_editor->right_saved_dirty    = curr_gradient->dirty;
  4633.   g_editor->right_saved_segments = cpopup_save_selection ();
  4634.  
  4635.   cpopup_create_color_dialog (_("Right endpoint's color"),
  4636.                   g_editor->control_sel_r->r1,
  4637.                   g_editor->control_sel_r->g1,
  4638.                   g_editor->control_sel_r->b1,
  4639.                   g_editor->control_sel_r->a1,
  4640.                   (GtkSignalFunc) cpopup_right_color_changed,
  4641.                   (GtkSignalFunc) cpopup_right_color_dialog_ok,
  4642.                   (GtkSignalFunc) cpopup_right_color_dialog_cancel,
  4643.                   (GtkSignalFunc) cpopup_right_color_dialog_delete);
  4644.  
  4645.   gtk_widget_set_sensitive (g_editor->shell, FALSE);
  4646. }
  4647.  
  4648. static void
  4649. cpopup_right_color_changed (GtkWidget *widget,
  4650.                 gpointer   data)
  4651. {
  4652.   GtkColorSelection *cs;
  4653.   double             r, g, b, a;
  4654.  
  4655.   cs = GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (data)->colorsel);
  4656.  
  4657.   cpopup_get_color_selection_color (cs, &r, &g, &b, &a);
  4658.  
  4659.   cpopup_blend_endpoints (g_editor->control_sel_l->r0,
  4660.               g_editor->control_sel_l->g0,
  4661.               g_editor->control_sel_l->b0,
  4662.               g_editor->control_sel_l->a0,
  4663.               r, g, b, a,
  4664.               TRUE, TRUE);
  4665.  
  4666.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  4667. }
  4668.  
  4669. static void
  4670. cpopup_right_color_dialog_ok (GtkWidget *widget,
  4671.                   gpointer   data)
  4672. {
  4673.   cpopup_right_color_changed (widget, data);
  4674.  
  4675.   curr_gradient->dirty = TRUE;
  4676.   cpopup_free_selection (g_editor->right_saved_segments);
  4677.  
  4678.   gtk_widget_destroy (GTK_WIDGET (data));
  4679.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  4680. }
  4681.  
  4682. static void
  4683. cpopup_right_color_dialog_cancel (GtkWidget *widget,
  4684.                   gpointer   data)
  4685. {
  4686.   curr_gradient->dirty = g_editor->right_saved_dirty;
  4687.   cpopup_replace_selection (g_editor->right_saved_segments);
  4688.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  4689.  
  4690.   gtk_widget_destroy (GTK_WIDGET (data));
  4691.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  4692. }
  4693.  
  4694. static int
  4695. cpopup_right_color_dialog_delete (GtkWidget *widget,
  4696.                   GdkEvent  *event,
  4697.                   gpointer   data)
  4698. {
  4699.   cpopup_right_color_dialog_cancel (widget, data);
  4700.  
  4701.   return TRUE;
  4702. }
  4703.  
  4704. /***** Blending menu *****/
  4705.  
  4706. static GtkWidget *
  4707. cpopup_create_blending_menu (void)
  4708. {
  4709.   GtkWidget *menu;
  4710.   GtkWidget *menuitem;
  4711.   GSList    *group;
  4712.   gint i;
  4713.   gint num_items;
  4714.  
  4715.   menu  = gtk_menu_new ();
  4716.   group = NULL;
  4717.  
  4718.   num_items = (sizeof (g_editor->control_blending_items) /
  4719.            sizeof (g_editor->control_blending_items[0]));
  4720.  
  4721.   for (i = 0; i < num_items; i++)
  4722.     {
  4723.       if (i == (num_items - 1))
  4724.     menuitem = gtk_radio_menu_item_new_with_label(group, _("(Varies)"));
  4725.       else
  4726.     menuitem =
  4727.       gtk_radio_menu_item_new_with_label (group,
  4728.                           gettext (blending_types[i]));
  4729.  
  4730.       group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  4731.  
  4732.       gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  4733.               (GtkSignalFunc) cpopup_blending_callback,
  4734.               (gpointer) ((long) i));
  4735.  
  4736.       gtk_menu_append (GTK_MENU (menu), menuitem);
  4737.       gtk_widget_show (menuitem);
  4738.  
  4739.       g_editor->control_blending_items[i] = menuitem;
  4740.     }
  4741.  
  4742.   /* "Varies" is always disabled */
  4743.   gtk_widget_set_sensitive (g_editor->control_blending_items[num_items - 1], FALSE);
  4744.  
  4745.   return menu;
  4746. }
  4747.  
  4748. static void
  4749. cpopup_blending_callback (GtkWidget *widget,
  4750.               gpointer   data)
  4751. {
  4752.   grad_type_t     type;
  4753.   grad_segment_t *seg, *aseg;
  4754.  
  4755.   if (!GTK_CHECK_MENU_ITEM (widget)->active)
  4756.     return; /* Do nothing if the menu item is being deactivated */
  4757.  
  4758.   type = (grad_type_t) data;
  4759.   seg  = g_editor->control_sel_l;
  4760.  
  4761.   do
  4762.     {
  4763.       seg->type = type;
  4764.  
  4765.       aseg = seg;
  4766.       seg  = seg->next;
  4767.     }
  4768.   while (aseg != g_editor->control_sel_r);
  4769.  
  4770.   curr_gradient->dirty = TRUE;
  4771.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  4772. }
  4773.  
  4774. /***** Coloring menu *****/
  4775.  
  4776. static GtkWidget *
  4777. cpopup_create_coloring_menu (void)
  4778. {
  4779.   GtkWidget *menu;
  4780.   GtkWidget *menuitem;
  4781.   GSList    *group;
  4782.   gint i;
  4783.   gint num_items;
  4784.  
  4785.   menu  = gtk_menu_new ();
  4786.   group = NULL;
  4787.  
  4788.   num_items = (sizeof (g_editor->control_coloring_items) /
  4789.            sizeof (g_editor->control_coloring_items[0]));
  4790.  
  4791.   for (i = 0; i < num_items; i++)
  4792.     {
  4793.       if (i == (num_items - 1))
  4794.     menuitem = gtk_radio_menu_item_new_with_label(group, _("(Varies)"));
  4795.       else
  4796.     menuitem = gtk_radio_menu_item_new_with_label (group, gettext (coloring_types[i]));
  4797.  
  4798.       group = gtk_radio_menu_item_group (GTK_RADIO_MENU_ITEM (menuitem));
  4799.  
  4800.       gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  4801.               (GtkSignalFunc) cpopup_coloring_callback,
  4802.               (gpointer) ((long) i));
  4803.  
  4804.       gtk_menu_append (GTK_MENU (menu), menuitem);
  4805.       gtk_widget_show (menuitem);
  4806.  
  4807.       g_editor->control_coloring_items[i] = menuitem;
  4808.     }
  4809.  
  4810.   /* "Varies" is always disabled */
  4811.   gtk_widget_set_sensitive (g_editor->control_coloring_items[num_items - 1], FALSE);
  4812.  
  4813.   return menu;
  4814. }
  4815.  
  4816. static void
  4817. cpopup_coloring_callback (GtkWidget *widget,
  4818.               gpointer   data)
  4819. {
  4820.   grad_color_t    color;
  4821.   grad_segment_t *seg, *aseg;
  4822.  
  4823.   if (! GTK_CHECK_MENU_ITEM (widget)->active)
  4824.     return; /* Do nothing if the menu item is being deactivated */
  4825.  
  4826.   color = (grad_color_t) data;
  4827.   seg   = g_editor->control_sel_l;
  4828.  
  4829.   do
  4830.     {
  4831.       seg->color = color;
  4832.  
  4833.       aseg = seg;
  4834.       seg  = seg->next;
  4835.     }
  4836.   while (aseg != g_editor->control_sel_r);
  4837.  
  4838.   curr_gradient->dirty = TRUE;
  4839.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  4840. }
  4841.  
  4842. /*****/
  4843.  
  4844. static void
  4845. cpopup_split_midpoint_callback (GtkWidget *widget,
  4846.                 gpointer   data)
  4847. {
  4848.   grad_segment_t *seg, *lseg, *rseg;
  4849.  
  4850.   seg = g_editor->control_sel_l;
  4851.  
  4852.   do
  4853.     {
  4854.       cpopup_split_midpoint (seg, &lseg, &rseg);
  4855.       seg = rseg->next;
  4856.     }
  4857.   while (lseg != g_editor->control_sel_r);
  4858.  
  4859.   g_editor->control_sel_r = rseg;
  4860.  
  4861.   curr_gradient->last_visited = NULL; /* Force re-search */
  4862.   curr_gradient->dirty = TRUE;
  4863.   ed_update_editor (GRAD_UPDATE_GRADIENT | GRAD_UPDATE_CONTROL);
  4864. }
  4865.  
  4866. static void
  4867. cpopup_split_midpoint (grad_segment_t  *lseg,
  4868.                grad_segment_t **newl,
  4869.                grad_segment_t **newr)
  4870. {
  4871.   double          r, g, b, a;
  4872.   grad_segment_t *newseg;
  4873.  
  4874.   /* Get color at original segment's midpoint */
  4875.   gradient_get_color_at (curr_gradient, lseg->middle, &r, &g, &b, &a);
  4876.  
  4877.   /* Create a new segment and insert it in the list */
  4878.  
  4879.   newseg = seg_new_segment();
  4880.  
  4881.   newseg->prev = lseg;
  4882.   newseg->next = lseg->next;
  4883.  
  4884.   lseg->next = newseg;
  4885.  
  4886.   if (newseg->next)
  4887.     newseg->next->prev = newseg;
  4888.  
  4889.   /* Set coordinates of new segment */
  4890.  
  4891.   newseg->left   = lseg->middle;
  4892.   newseg->right  = lseg->right;
  4893.   newseg->middle = (newseg->left + newseg->right) / 2.0;
  4894.  
  4895.   /* Set coordinates of original segment */
  4896.  
  4897.   lseg->right  = newseg->left;
  4898.   lseg->middle = (lseg->left + lseg->right) / 2.0;
  4899.  
  4900.   /* Set colors of both segments */
  4901.  
  4902.   newseg->r1 = lseg->r1;
  4903.   newseg->g1 = lseg->g1;
  4904.   newseg->b1 = lseg->b1;
  4905.   newseg->a1 = lseg->a1;
  4906.  
  4907.   lseg->r1 = newseg->r0 = r;
  4908.   lseg->g1 = newseg->g0 = g;
  4909.   lseg->b1 = newseg->b0 = b;
  4910.   lseg->a1 = newseg->a0 = a;
  4911.  
  4912.   /* Set parameters of new segment */
  4913.  
  4914.   newseg->type  = lseg->type;
  4915.   newseg->color = lseg->color;
  4916.  
  4917.   /* Done */
  4918.  
  4919.   *newl = lseg;
  4920.   *newr = newseg;
  4921. }
  4922.  
  4923. /*****/
  4924.  
  4925. static void
  4926. cpopup_split_uniform_callback (GtkWidget *widget,
  4927.                    gpointer   data)
  4928. {
  4929.   GtkWidget *dialog;
  4930.   GtkWidget *vbox;
  4931.   GtkWidget *label;
  4932.   GtkWidget *scale;
  4933.   GtkObject *scale_data;
  4934.  
  4935.   /*  Create dialog window  */
  4936.   dialog =
  4937.     gimp_dialog_new ((g_editor->control_sel_l == g_editor->control_sel_r) ?
  4938.              _("Split segment uniformly") :
  4939.              _("Split segments uniformly"),
  4940.              "gradient_segment_split_uniformly",
  4941.              gimp_standard_help_func,
  4942.              "dialogs/gradient_editor/split_segments_uniformly.html",
  4943.              GTK_WIN_POS_MOUSE,
  4944.              FALSE, TRUE, FALSE,
  4945.  
  4946.              _("Split"), cpopup_split_uniform_split_callback,
  4947.              NULL, NULL, NULL, TRUE, FALSE,
  4948.              _("Cancel"), cpopup_split_uniform_cancel_callback,
  4949.              NULL, NULL, NULL, FALSE, TRUE,
  4950.  
  4951.              NULL);
  4952.  
  4953.   /*  The main vbox  */
  4954.   vbox = gtk_vbox_new (FALSE, 0);
  4955.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
  4956.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
  4957.   gtk_widget_show (vbox);
  4958.  
  4959.   /*  Instructions  */
  4960.   label = gtk_label_new (_("Please select the number of uniform parts"));
  4961.   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  4962.   gtk_widget_show (label);
  4963.  
  4964.   label =
  4965.     gtk_label_new ((g_editor->control_sel_l == g_editor->control_sel_r) ?
  4966.            _("in which you want to split the selected segment") :
  4967.            _("in which you want to split the segments in the selection"));
  4968.   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  4969.   gtk_widget_show (label);
  4970.  
  4971.   /*  Scale  */
  4972.   g_editor->split_parts = 2;
  4973.   scale_data  = gtk_adjustment_new (2.0, 2.0, 21.0, 1.0, 1.0, 1.0);
  4974.  
  4975.   scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data));
  4976.   gtk_scale_set_digits (GTK_SCALE (scale), 0);
  4977.   gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
  4978.   gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 4);
  4979.   gtk_widget_show (scale);
  4980.  
  4981.   gtk_signal_connect (scale_data, "value_changed",
  4982.               (GtkSignalFunc) cpopup_split_uniform_scale_update,
  4983.               NULL);
  4984.  
  4985.   /*  Show!  */
  4986.   gtk_widget_show (dialog);
  4987.   gtk_widget_set_sensitive (g_editor->shell, FALSE);
  4988. }
  4989.  
  4990. static void
  4991. cpopup_split_uniform_scale_update (GtkAdjustment *adjustment,
  4992.                    gpointer       data)
  4993. {
  4994.   g_editor->split_parts = (gint) (adjustment->value + 0.5);
  4995. }
  4996.  
  4997. static void
  4998. cpopup_split_uniform_split_callback (GtkWidget *widget,
  4999.                      gpointer   data)
  5000. {
  5001.   grad_segment_t *seg, *aseg, *lseg, *rseg, *lsel;
  5002.  
  5003.   gtk_widget_destroy (GTK_WIDGET (data));
  5004.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  5005.  
  5006.   seg  = g_editor->control_sel_l;
  5007.   lsel = NULL;
  5008.  
  5009.   do
  5010.     {
  5011.       aseg = seg;
  5012.  
  5013.       cpopup_split_uniform (seg, g_editor->split_parts, &lseg, &rseg);
  5014.  
  5015.       if (seg == g_editor->control_sel_l)
  5016.     lsel = lseg;
  5017.  
  5018.       seg = rseg->next;
  5019.     }
  5020.   while (aseg != g_editor->control_sel_r);
  5021.  
  5022.   g_editor->control_sel_l = lsel;
  5023.   g_editor->control_sel_r = rseg;
  5024.  
  5025.   curr_gradient->last_visited = NULL; /* Force re-search */
  5026.   curr_gradient->dirty = TRUE;
  5027.   ed_update_editor (GRAD_UPDATE_GRADIENT | GRAD_UPDATE_CONTROL);
  5028. }
  5029.  
  5030. static void
  5031. cpopup_split_uniform_cancel_callback (GtkWidget *widget,
  5032.                       gpointer   data)
  5033. {
  5034.   gtk_widget_destroy (GTK_WIDGET (data));
  5035.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  5036. }
  5037.  
  5038. static void
  5039. cpopup_split_uniform (grad_segment_t  *lseg,
  5040.               int              parts,
  5041.               grad_segment_t **newl,
  5042.               grad_segment_t **newr)
  5043. {
  5044.   grad_segment_t *seg, *prev, *tmp;
  5045.   gdouble          seg_len;
  5046.   gint             i;
  5047.  
  5048.   seg_len = (lseg->right - lseg->left) / parts; /* Length of divisions */
  5049.  
  5050.   seg  = NULL;
  5051.   prev = NULL;
  5052.   tmp  = NULL;
  5053.  
  5054.   for (i = 0; i < parts; i++)
  5055.     {
  5056.       seg = seg_new_segment();
  5057.  
  5058.       if (i == 0)
  5059.     tmp = seg; /* Remember first segment */
  5060.  
  5061.       seg->left   = lseg->left + i * seg_len;
  5062.       seg->right  = lseg->left + (i + 1) * seg_len;
  5063.       seg->middle = (seg->left + seg->right) / 2.0;
  5064.  
  5065.       gradient_get_color_at (curr_gradient, seg->left,
  5066.                  &seg->r0, &seg->g0, &seg->b0, &seg->a0);
  5067.       gradient_get_color_at (curr_gradient, seg->right,
  5068.                  &seg->r1, &seg->g1, &seg->b1, &seg->a1);
  5069.  
  5070.       seg->type  = lseg->type;
  5071.       seg->color = lseg->color;
  5072.  
  5073.       seg->prev = prev;
  5074.       seg->next = NULL;
  5075.  
  5076.       if (prev)
  5077.     prev->next = seg;
  5078.  
  5079.       prev = seg;
  5080.     }
  5081.  
  5082.   /* Fix edges */
  5083.  
  5084.   tmp->r0 = lseg->r0;
  5085.   tmp->g0 = lseg->g0;
  5086.   tmp->b0 = lseg->b0;
  5087.   tmp->a0 = lseg->a0;
  5088.  
  5089.   seg->r1 = lseg->r1;
  5090.   seg->g1 = lseg->g1;
  5091.   seg->b1 = lseg->b1;
  5092.   seg->a1 = lseg->a1;
  5093.  
  5094.   tmp->left  = lseg->left;
  5095.   seg->right = lseg->right; /* To squish accumulative error */
  5096.  
  5097.   /* Link in list */
  5098.  
  5099.   tmp->prev = lseg->prev;
  5100.   seg->next = lseg->next;
  5101.  
  5102.   if (lseg->prev)
  5103.     lseg->prev->next = tmp;
  5104.   else
  5105.     curr_gradient->segments = tmp; /* We are on leftmost segment */
  5106.  
  5107.   if (lseg->next)
  5108.     lseg->next->prev = seg;
  5109.  
  5110.   curr_gradient->last_visited = NULL; /* Force re-search */
  5111.  
  5112.   /* Done */
  5113.  
  5114.   *newl = tmp;
  5115.   *newr = seg;
  5116.  
  5117.   /* Delete old segment */
  5118.  
  5119.   seg_free_segment (lseg);
  5120. }
  5121.  
  5122. /*****/
  5123.  
  5124. static void
  5125. cpopup_delete_callback (GtkWidget *widget,
  5126.             gpointer   data)
  5127. {
  5128.   grad_segment_t *lseg, *rseg, *seg, *aseg, *next;
  5129.   double          join;
  5130.  
  5131.   /* Remember segments to the left and to the right of the selection */
  5132.  
  5133.   lseg = g_editor->control_sel_l->prev;
  5134.   rseg = g_editor->control_sel_r->next;
  5135.  
  5136.   /* Cannot delete all the segments in the gradient */
  5137.  
  5138.   if ((lseg == NULL) && (rseg == NULL))
  5139.     return;
  5140.  
  5141.   /* Calculate join point */
  5142.  
  5143.   join = (g_editor->control_sel_l->left + g_editor->control_sel_r->right) / 2.0;
  5144.  
  5145.   if (lseg == NULL)
  5146.     join = 0.0;
  5147.   else if (rseg == NULL)
  5148.     join = 1.0;
  5149.  
  5150.   /* Move segments */
  5151.  
  5152.   if (lseg != NULL)
  5153.     control_compress_range (lseg, lseg, lseg->left, join);
  5154.  
  5155.   if (rseg != NULL)
  5156.     control_compress_range (rseg, rseg, join, rseg->right);
  5157.  
  5158.   /* Link */
  5159.  
  5160.   if (lseg)
  5161.     lseg->next = rseg;
  5162.  
  5163.   if (rseg)
  5164.     rseg->prev = lseg;
  5165.  
  5166.   /* Delete old segments */
  5167.  
  5168.   seg = g_editor->control_sel_l;
  5169.  
  5170.   do
  5171.     {
  5172.       next = seg->next;
  5173.       aseg = seg;
  5174.  
  5175.       seg_free_segment (seg);
  5176.  
  5177.       seg = next;
  5178.     }
  5179.   while (aseg != g_editor->control_sel_r);
  5180.  
  5181.   /* Change selection */
  5182.  
  5183.   if (rseg)
  5184.     {
  5185.       g_editor->control_sel_l = rseg;
  5186.       g_editor->control_sel_r = rseg;
  5187.     }
  5188.   else
  5189.     {
  5190.       g_editor->control_sel_l = lseg;
  5191.       g_editor->control_sel_r = lseg;
  5192.     }
  5193.  
  5194.   if (lseg == NULL)
  5195.     curr_gradient->segments = rseg;
  5196.  
  5197.   /* Done */
  5198.  
  5199.   curr_gradient->last_visited = NULL; /* Force re-search */
  5200.   curr_gradient->dirty = TRUE;
  5201.  
  5202.   ed_update_editor (GRAD_UPDATE_GRADIENT | GRAD_UPDATE_CONTROL);
  5203. }
  5204.  
  5205. /*****/
  5206.  
  5207. static void
  5208. cpopup_recenter_callback (GtkWidget *wiodget,
  5209.               gpointer   data)
  5210. {
  5211.   grad_segment_t *seg, *aseg;
  5212.  
  5213.   seg = g_editor->control_sel_l;
  5214.  
  5215.   do
  5216.     {
  5217.       seg->middle = (seg->left + seg->right) / 2.0;
  5218.  
  5219.       aseg = seg;
  5220.       seg  = seg->next;
  5221.     }
  5222.   while (aseg != g_editor->control_sel_r);
  5223.  
  5224.   curr_gradient->dirty = TRUE;
  5225.   ed_update_editor (GRAD_UPDATE_GRADIENT | GRAD_UPDATE_CONTROL);
  5226. }
  5227.  
  5228. /*****/
  5229.  
  5230. static void
  5231. cpopup_redistribute_callback (GtkWidget *widget,
  5232.                   gpointer   data)
  5233. {
  5234.   grad_segment_t *seg, *aseg;
  5235.   double          left, right, seg_len;
  5236.   int             num_segs;
  5237.   int             i;
  5238.  
  5239.   /* Count number of segments in selection */
  5240.  
  5241.   num_segs = 0;
  5242.   seg      = g_editor->control_sel_l;
  5243.  
  5244.   do
  5245.     {
  5246.       num_segs++;
  5247.       aseg = seg;
  5248.       seg  = seg->next;
  5249.     }
  5250.   while (aseg != g_editor->control_sel_r);
  5251.  
  5252.   /* Calculate new segment length */
  5253.  
  5254.   left    = g_editor->control_sel_l->left;
  5255.   right   = g_editor->control_sel_r->right;
  5256.   seg_len = (right - left) / num_segs;
  5257.  
  5258.   /* Redistribute */
  5259.  
  5260.   seg = g_editor->control_sel_l;
  5261.  
  5262.   for (i = 0; i < num_segs; i++)
  5263.     {
  5264.       seg->left   = left + i * seg_len;
  5265.       seg->right  = left + (i + 1) * seg_len;
  5266.       seg->middle = (seg->left + seg->right) / 2.0;
  5267.  
  5268.       seg = seg->next;
  5269.     }
  5270.  
  5271.   /* Fix endpoints to squish accumulative error */
  5272.  
  5273.   g_editor->control_sel_l->left  = left;
  5274.   g_editor->control_sel_r->right = right;
  5275.  
  5276.   /* Done */
  5277.  
  5278.   curr_gradient->dirty = TRUE;
  5279.   ed_update_editor (GRAD_UPDATE_GRADIENT | GRAD_UPDATE_CONTROL);
  5280. }
  5281.  
  5282. /***** Control popup -> selection options functions *****/
  5283.  
  5284. static GtkWidget *
  5285. cpopup_create_sel_ops_menu (void)
  5286. {
  5287.   GtkWidget     *menu;
  5288.   GtkWidget     *menuitem;
  5289.   GtkAccelGroup *accel_group;
  5290.  
  5291.   menu = gtk_menu_new ();
  5292.   accel_group = g_editor->accel_group;
  5293.  
  5294.   gtk_menu_set_accel_group (GTK_MENU (menu), accel_group);
  5295.  
  5296.   /* Flip */
  5297.   menuitem =
  5298.     cpopup_create_menu_item_with_label ("", &g_editor->control_flip_label);
  5299.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  5300.               (GtkSignalFunc) cpopup_flip_callback,
  5301.               NULL);
  5302.   gtk_menu_append (GTK_MENU (menu), menuitem);
  5303.   gtk_widget_show (menuitem);
  5304.   gtk_widget_add_accelerator (menuitem, "activate",
  5305.                   accel_group,
  5306.                   'F', 0,
  5307.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  5308.  
  5309.   /* Replicate */
  5310.   menuitem =
  5311.     cpopup_create_menu_item_with_label ("", &g_editor->control_replicate_label);
  5312.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  5313.               (GtkSignalFunc) cpopup_replicate_callback,
  5314.               NULL);
  5315.   gtk_menu_append (GTK_MENU (menu), menuitem);
  5316.   gtk_widget_show (menuitem);
  5317.   gtk_widget_add_accelerator (menuitem, "activate",
  5318.                   accel_group,
  5319.                   'M', 0,
  5320.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  5321.  
  5322.   /* Blend colors / opacity */
  5323.   menuitem = gtk_menu_item_new ();
  5324.   gtk_menu_append (GTK_MENU (menu), menuitem);
  5325.   gtk_widget_show (menuitem);
  5326.  
  5327.   menuitem = gtk_menu_item_new_with_label (_("Blend endpoints' colors"));
  5328.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  5329.               (GtkSignalFunc) cpopup_blend_colors,
  5330.               NULL);
  5331.   gtk_menu_append (GTK_MENU (menu), menuitem);
  5332.   gtk_widget_show (menuitem);
  5333.   g_editor->control_blend_colors_menu_item = menuitem;
  5334.   gtk_widget_add_accelerator (menuitem, "activate",
  5335.                   accel_group,
  5336.                   'B', 0,
  5337.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  5338.  
  5339.   menuitem = gtk_menu_item_new_with_label (_("Blend endpoints' opacity"));
  5340.   gtk_signal_connect (GTK_OBJECT (menuitem), "activate",
  5341.               (GtkSignalFunc) cpopup_blend_opacity,
  5342.               NULL);
  5343.   gtk_menu_append (GTK_MENU (menu), menuitem);
  5344.   gtk_widget_show (menuitem);
  5345.   gtk_widget_add_accelerator (menuitem, "activate",
  5346.                   accel_group,
  5347.                   'B', GDK_CONTROL_MASK,
  5348.                   GTK_ACCEL_VISIBLE | GTK_ACCEL_LOCKED);
  5349.   g_editor->control_blend_opacity_menu_item = menuitem;
  5350.  
  5351.   return menu;
  5352. }
  5353.  
  5354. /*****/
  5355.  
  5356. static void
  5357. cpopup_flip_callback (GtkWidget *widget,
  5358.               gpointer   data)
  5359. {
  5360.   grad_segment_t *oseg, *oaseg;
  5361.   grad_segment_t *seg, *prev, *tmp;
  5362.   grad_segment_t *lseg, *rseg;
  5363.   double          left, right;
  5364.  
  5365.   left  = g_editor->control_sel_l->left;
  5366.   right = g_editor->control_sel_r->right;
  5367.  
  5368.   /* Build flipped segments */
  5369.  
  5370.   prev = NULL;
  5371.   oseg = g_editor->control_sel_r;
  5372.   tmp  = NULL;
  5373.  
  5374.   do
  5375.     {
  5376.       seg = seg_new_segment ();
  5377.  
  5378.       if (prev == NULL)
  5379.     {
  5380.       seg->left = left;
  5381.       tmp = seg; /* Remember first segment */
  5382.     }
  5383.       else
  5384.     seg->left = left + right - oseg->right;
  5385.  
  5386.       seg->middle = left + right - oseg->middle;
  5387.       seg->right  = left + right - oseg->left;
  5388.  
  5389.       seg->r0 = oseg->r1;
  5390.       seg->g0 = oseg->g1;
  5391.       seg->b0 = oseg->b1;
  5392.       seg->a0 = oseg->a1;
  5393.  
  5394.       seg->r1 = oseg->r0;
  5395.       seg->g1 = oseg->g0;
  5396.       seg->b1 = oseg->b0;
  5397.       seg->a1 = oseg->a0;
  5398.  
  5399.       switch (oseg->type)
  5400.     {
  5401.     case GRAD_SPHERE_INCREASING:
  5402.       seg->type = GRAD_SPHERE_DECREASING;
  5403.       break;
  5404.  
  5405.     case GRAD_SPHERE_DECREASING:
  5406.       seg->type = GRAD_SPHERE_INCREASING;
  5407.       break;
  5408.  
  5409.     default:
  5410.       seg->type = oseg->type;
  5411.     }
  5412.  
  5413.       switch (oseg->color)
  5414.     {
  5415.     case GRAD_HSV_CCW:
  5416.       seg->color = GRAD_HSV_CW;
  5417.       break;
  5418.  
  5419.     case GRAD_HSV_CW:
  5420.       seg->color = GRAD_HSV_CCW;
  5421.       break;
  5422.  
  5423.     default:
  5424.       seg->color = oseg->color;
  5425.     }
  5426.  
  5427.       seg->prev = prev;
  5428.       seg->next = NULL;
  5429.  
  5430.       if (prev)
  5431.     prev->next = seg;
  5432.  
  5433.       prev = seg;
  5434.  
  5435.       oaseg = oseg;
  5436.       oseg  = oseg->prev; /* Move backwards! */
  5437.     }
  5438.   while (oaseg != g_editor->control_sel_l);
  5439.  
  5440.   seg->right = right; /* Squish accumulative error */
  5441.  
  5442.   /* Free old segments */
  5443.  
  5444.   lseg = g_editor->control_sel_l->prev;
  5445.   rseg = g_editor->control_sel_r->next;
  5446.  
  5447.   oseg = g_editor->control_sel_l;
  5448.  
  5449.   do
  5450.     {
  5451.       oaseg = oseg->next;
  5452.       seg_free_segment (oseg);
  5453.       oseg = oaseg;
  5454.     }
  5455.   while (oaseg != rseg);
  5456.  
  5457.   /* Link in new segments */
  5458.  
  5459.   if (lseg)
  5460.     lseg->next = tmp;
  5461.   else
  5462.     curr_gradient->segments = tmp;
  5463.  
  5464.   tmp->prev = lseg;
  5465.  
  5466.   seg->next = rseg;
  5467.  
  5468.   if (rseg)
  5469.     rseg->prev = seg;
  5470.  
  5471.   /* Reset selection */
  5472.  
  5473.   g_editor->control_sel_l = tmp;
  5474.   g_editor->control_sel_r = seg;
  5475.  
  5476.   /* Done */
  5477.  
  5478.   curr_gradient->last_visited = NULL; /* Force re-search */
  5479.   curr_gradient->dirty = TRUE;
  5480.  
  5481.   ed_update_editor (GRAD_UPDATE_GRADIENT | GRAD_UPDATE_CONTROL);
  5482. }
  5483.  
  5484. /*****/
  5485.  
  5486. static void
  5487. cpopup_replicate_callback (GtkWidget *widget,
  5488.                gpointer   data)
  5489. {
  5490.   GtkWidget *dialog;
  5491.   GtkWidget *vbox;
  5492.   GtkWidget *label;
  5493.   GtkWidget *scale;
  5494.   GtkObject *scale_data;
  5495.  
  5496.   /*  Create dialog window  */
  5497.   dialog =
  5498.     gimp_dialog_new ((g_editor->control_sel_l == g_editor->control_sel_r) ?
  5499.              _("Replicate segment") :
  5500.              _("Replicate selection"),
  5501.              "gradient_segment_replicate",
  5502.              gimp_standard_help_func,
  5503.              "dialogs/gradient_editor/replicate_segment.html",
  5504.              GTK_WIN_POS_MOUSE,
  5505.              FALSE, TRUE, FALSE,
  5506.  
  5507.              _("Replicate"), cpopup_do_replicate_callback,
  5508.              NULL, NULL, NULL, FALSE, FALSE,
  5509.              _("Cancel"), cpopup_replicate_cancel_callback,
  5510.              NULL, NULL, NULL, TRUE, TRUE,
  5511.  
  5512.              NULL);
  5513.  
  5514.   vbox = gtk_vbox_new (FALSE, 0);
  5515.   gtk_container_set_border_width (GTK_CONTAINER (vbox), 6);
  5516.   gtk_container_add (GTK_CONTAINER (GTK_DIALOG (dialog)->vbox), vbox);
  5517.   gtk_widget_show (vbox);
  5518.  
  5519.   /*  Instructions  */
  5520.   label = gtk_label_new (_("Please select the number of times"));
  5521.   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  5522.   gtk_widget_show (label);
  5523.  
  5524.   label = gtk_label_new ((g_editor->control_sel_l == g_editor->control_sel_r) ?
  5525.              _("you want to replicate the selected segment") :
  5526.              _("you want to replicate the selection"));
  5527.   gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
  5528.   gtk_widget_show (label);
  5529.  
  5530.   /*  Scale  */
  5531.   g_editor->replicate_times = 2;
  5532.   scale_data  = gtk_adjustment_new (2.0, 2.0, 21.0, 1.0, 1.0, 1.0);
  5533.  
  5534.   scale = gtk_hscale_new (GTK_ADJUSTMENT (scale_data));
  5535.   gtk_scale_set_digits (GTK_SCALE (scale), 0);
  5536.   gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_TOP);
  5537.   gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, TRUE, 4);
  5538.   gtk_widget_show (scale);
  5539.  
  5540.   gtk_signal_connect (scale_data, "value_changed",
  5541.               (GtkSignalFunc) cpopup_replicate_scale_update,
  5542.               NULL);
  5543.  
  5544.   /*  Show!  */
  5545.   gtk_widget_show (dialog);
  5546.   gtk_widget_set_sensitive (g_editor->shell, FALSE);
  5547. }
  5548.  
  5549. static void
  5550. cpopup_replicate_scale_update (GtkAdjustment *adjustment,
  5551.                    gpointer       data)
  5552. {
  5553.   g_editor->replicate_times = (int) (adjustment->value + 0.5);
  5554. }
  5555.  
  5556. static void
  5557. cpopup_do_replicate_callback (GtkWidget *widget,
  5558.                   gpointer   data)
  5559. {
  5560.   gdouble          sel_left, sel_right, sel_len;
  5561.   gdouble          new_left;
  5562.   gdouble          factor;
  5563.   grad_segment_t  *prev, *seg, *tmp;
  5564.   grad_segment_t  *oseg, *oaseg;
  5565.   grad_segment_t  *lseg, *rseg;
  5566.   gint             i;
  5567.  
  5568.   gtk_widget_destroy (GTK_WIDGET (data));
  5569.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  5570.  
  5571.   /* Remember original parameters */
  5572.   sel_left  = g_editor->control_sel_l->left;
  5573.   sel_right = g_editor->control_sel_r->right;
  5574.   sel_len   = sel_right - sel_left;
  5575.  
  5576.   factor = 1.0 / g_editor->replicate_times;
  5577.  
  5578.   /* Build replicated segments */
  5579.  
  5580.   prev = NULL;
  5581.   seg  = NULL;
  5582.   tmp  = NULL;
  5583.  
  5584.   for (i = 0; i < g_editor->replicate_times; i++)
  5585.     {
  5586.       /* Build one cycle */
  5587.  
  5588.       new_left  = sel_left + i * factor * sel_len;
  5589.  
  5590.       oseg = g_editor->control_sel_l;
  5591.  
  5592.       do
  5593.     {
  5594.       seg = seg_new_segment();
  5595.  
  5596.       if (prev == NULL)
  5597.         {
  5598.           seg->left = sel_left;
  5599.           tmp = seg; /* Remember first segment */
  5600.         }
  5601.       else
  5602.         seg->left = new_left + factor * (oseg->left - sel_left);
  5603.  
  5604.       seg->middle = new_left + factor * (oseg->middle - sel_left);
  5605.       seg->right  = new_left + factor * (oseg->right - sel_left);
  5606.  
  5607.       seg->r0 = oseg->r0;
  5608.       seg->g0 = oseg->g0;
  5609.       seg->b0 = oseg->b0;
  5610.       seg->a0 = oseg->a0;
  5611.  
  5612.       seg->r1 = oseg->r1;
  5613.       seg->g1 = oseg->g1;
  5614.       seg->b1 = oseg->b1;
  5615.       seg->a1 = oseg->a1;
  5616.  
  5617.       seg->type  = oseg->type;
  5618.       seg->color = oseg->color;
  5619.  
  5620.       seg->prev = prev;
  5621.       seg->next = NULL;
  5622.  
  5623.       if (prev)
  5624.         prev->next = seg;
  5625.  
  5626.       prev = seg;
  5627.  
  5628.       oaseg = oseg;
  5629.       oseg  = oseg->next;
  5630.     }
  5631.       while (oaseg != g_editor->control_sel_r);
  5632.     }
  5633.  
  5634.   seg->right = sel_right; /* Squish accumulative error */
  5635.  
  5636.   /* Free old segments */
  5637.  
  5638.   lseg = g_editor->control_sel_l->prev;
  5639.   rseg = g_editor->control_sel_r->next;
  5640.  
  5641.   oseg = g_editor->control_sel_l;
  5642.  
  5643.   do
  5644.     {
  5645.       oaseg = oseg->next;
  5646.       seg_free_segment(oseg);
  5647.       oseg = oaseg;
  5648.     }
  5649.   while (oaseg != rseg);
  5650.  
  5651.   /* Link in new segments */
  5652.  
  5653.   if (lseg)
  5654.     lseg->next = tmp;
  5655.   else
  5656.     curr_gradient->segments = tmp;
  5657.  
  5658.   tmp->prev = lseg;
  5659.  
  5660.   seg->next = rseg;
  5661.  
  5662.   if (rseg)
  5663.     rseg->prev = seg;
  5664.  
  5665.   /* Reset selection */
  5666.  
  5667.   g_editor->control_sel_l = tmp;
  5668.   g_editor->control_sel_r = seg;
  5669.  
  5670.   /* Done */
  5671.  
  5672.   curr_gradient->last_visited = NULL; /* Force re-search */
  5673.   curr_gradient->dirty = TRUE;
  5674.  
  5675.   ed_update_editor (GRAD_UPDATE_GRADIENT | GRAD_UPDATE_CONTROL);
  5676. }
  5677.  
  5678. static void
  5679. cpopup_replicate_cancel_callback (GtkWidget *widget,
  5680.                   gpointer   data)
  5681. {
  5682.   gtk_widget_destroy (GTK_WIDGET (data));
  5683.   gtk_widget_set_sensitive (g_editor->shell, TRUE);
  5684. }
  5685.  
  5686. /*****/
  5687.  
  5688. static void
  5689. cpopup_blend_colors (GtkWidget *widget,
  5690.              gpointer   data)
  5691. {
  5692.   cpopup_blend_endpoints (g_editor->control_sel_l->r0,
  5693.               g_editor->control_sel_l->g0,
  5694.               g_editor->control_sel_l->b0,
  5695.               g_editor->control_sel_l->a0,
  5696.               g_editor->control_sel_r->r1,
  5697.               g_editor->control_sel_r->g1,
  5698.               g_editor->control_sel_r->b1,
  5699.               g_editor->control_sel_r->a1,
  5700.               TRUE, FALSE);
  5701.  
  5702.   curr_gradient->dirty = TRUE;
  5703.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  5704. }
  5705.  
  5706. static void
  5707. cpopup_blend_opacity (GtkWidget *widget,
  5708.               gpointer   data)
  5709. {
  5710.   cpopup_blend_endpoints (g_editor->control_sel_l->r0,
  5711.               g_editor->control_sel_l->g0,
  5712.               g_editor->control_sel_l->b0,
  5713.               g_editor->control_sel_l->a0,
  5714.               g_editor->control_sel_r->r1,
  5715.               g_editor->control_sel_r->g1,
  5716.               g_editor->control_sel_r->b1,
  5717.               g_editor->control_sel_r->a1,
  5718.               FALSE, TRUE);
  5719.  
  5720.   curr_gradient->dirty = TRUE;
  5721.   ed_update_editor (GRAD_UPDATE_GRADIENT);
  5722. }
  5723.  
  5724. /***** Main blend function *****/
  5725.  
  5726. static void
  5727. cpopup_blend_endpoints (double r0, double g0, double b0, double a0,
  5728.             double r1, double g1, double b1, double a1,
  5729.             int blend_colors,
  5730.             int blend_opacity)
  5731. {
  5732.   double          dr, dg, db, da;
  5733.   double          left, len;
  5734.   grad_segment_t *seg, *aseg;
  5735.  
  5736.   dr = r1 - r0;
  5737.   dg = g1 - g0;
  5738.   db = b1 - b0;
  5739.   da = a1 - a0;
  5740.  
  5741.   left  = g_editor->control_sel_l->left;
  5742.   len   = g_editor->control_sel_r->right - left;
  5743.  
  5744.   seg = g_editor->control_sel_l;
  5745.  
  5746.   do
  5747.     {
  5748.       if (blend_colors)
  5749.     {
  5750.       seg->r0 = r0 + (seg->left - left) / len * dr;
  5751.       seg->g0 = g0 + (seg->left - left) / len * dg;
  5752.       seg->b0 = b0 + (seg->left - left) / len * db;
  5753.  
  5754.       seg->r1 = r0 + (seg->right - left) / len * dr;
  5755.       seg->g1 = g0 + (seg->right - left) / len * dg;
  5756.       seg->b1 = b0 + (seg->right - left) / len * db;
  5757.     }
  5758.  
  5759.       if (blend_opacity)
  5760.     {
  5761.       seg->a0 = a0 + (seg->left - left) / len * da;
  5762.       seg->a1 = a0 + (seg->right - left) / len * da;
  5763.     }
  5764.  
  5765.       aseg = seg;
  5766.       seg = seg->next;
  5767.     }
  5768.   while (aseg != g_editor->control_sel_r);
  5769. }
  5770.  
  5771. /***** Gradient functions *****/
  5772.  
  5773. static gradient_t *
  5774. grad_new_gradient (void)
  5775. {
  5776.   gradient_t *grad;
  5777.  
  5778.   grad = g_new (gradient_t, 1);
  5779.  
  5780.   grad->name            = NULL;
  5781.   grad->filename     = NULL;
  5782.   grad->segments     = NULL;
  5783.   grad->last_visited = NULL;
  5784.   grad->dirty        = FALSE;
  5785.   grad->pixmap       = NULL;
  5786.  
  5787.   return grad;
  5788. }
  5789.  
  5790. /*****/
  5791.  
  5792. static void
  5793. grad_free_gradient (gradient_t *grad)
  5794. {
  5795.   g_assert (grad != NULL);
  5796.  
  5797.   if (grad->name)
  5798.     g_free (grad->name);
  5799.  
  5800.   if (grad->segments)
  5801.     seg_free_segments (grad->segments);
  5802.  
  5803.   if (grad->filename)
  5804.     g_free (grad->filename);
  5805.  
  5806.   if (grad->pixmap)
  5807.     gdk_pixmap_unref (grad->pixmap);
  5808.  
  5809.   g_free (grad);
  5810. }
  5811.  
  5812. /*****/
  5813.  
  5814. static void
  5815. grad_save_all (gboolean need_free)
  5816. {
  5817.   GSList     *node;
  5818.   gradient_t *grad;
  5819.  
  5820.   for (node = gradients_list; node; node = g_slist_next (node))
  5821.     {
  5822.       grad = node->data;
  5823.  
  5824.       /* If gradient has dirty flag set, save it */
  5825.       if (grad->dirty)
  5826.     grad_save_gradient (grad, grad->filename);
  5827.  
  5828.       if (need_free)
  5829.     grad_free_gradient (grad);
  5830.     }
  5831. }
  5832.  
  5833. /*****/
  5834.  
  5835. static void
  5836. grad_free_gradients (void)
  5837. {
  5838.   grad_save_all (TRUE);  
  5839.  
  5840.   g_slist_free (gradients_list);
  5841.  
  5842.   num_gradients  = 0;
  5843.   gradients_list = NULL;
  5844.   curr_gradient  = NULL;
  5845.   dnd_gradient   = NULL;
  5846. }
  5847.  
  5848. /*****/
  5849.  
  5850. static void
  5851. grad_load_gradient (gchar *filename)
  5852. {
  5853.   FILE           *file;
  5854.   gradient_t     *grad;
  5855.   grad_segment_t *seg;
  5856.   grad_segment_t *prev;
  5857.   gint            num_segments;
  5858.   gint            i;
  5859.   gint            type, color;
  5860.   gchar           line[1024];
  5861.  
  5862.   g_assert (filename != NULL);
  5863.  
  5864.   file = fopen (filename, "rb");
  5865.   if (!file)
  5866.     return;
  5867.  
  5868.   fgets (line, 1024, file);
  5869.   if (strcmp (line, "GIMP Gradient\n") != 0)
  5870.     return;
  5871.  
  5872.   grad = grad_new_gradient ();
  5873.  
  5874.   grad->filename = g_strdup (filename);
  5875.   grad->name     = g_strdup (g_basename (filename));
  5876.  
  5877.   fgets (line, 1024, file);
  5878.   num_segments = atoi (line);
  5879.  
  5880.   if (num_segments < 1)
  5881.     {
  5882.       g_message ("grad_load_gradient(): "
  5883.                  "invalid number of segments in \"%s\"", filename);
  5884.       g_free (grad);
  5885.       return;
  5886.     }
  5887.  
  5888.   prev = NULL;
  5889.  
  5890.   for (i = 0; i < num_segments; i++)
  5891.     {
  5892.       seg = seg_new_segment ();
  5893.       seg->prev = prev;
  5894.  
  5895.       if (prev)
  5896.     prev->next = seg;
  5897.       else
  5898.     grad->segments = seg;
  5899.  
  5900.       fgets (line, 1024, file);
  5901.  
  5902.       if (sscanf (line, "%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%lf%d%d",
  5903.           &(seg->left), &(seg->middle), &(seg->right),
  5904.           &(seg->r0), &(seg->g0), &(seg->b0), &(seg->a0),
  5905.           &(seg->r1), &(seg->g1), &(seg->b1), &(seg->a1),
  5906.           &type, &color) != 13)
  5907.     {
  5908.       g_message ("grad_load_gradient(): badly formatted "
  5909.                      "gradient segment %d in \"%s\" --- bad things may "
  5910.                      "happen soon", i, filename);
  5911.     }
  5912.       else
  5913.     {
  5914.       seg->type  = (grad_type_t) type;
  5915.       seg->color = (grad_color_t) color;
  5916.     }
  5917.  
  5918.       prev = seg;
  5919.     }
  5920.  
  5921.   fclose (file);
  5922.  
  5923.   grad_insert_in_gradients_list (grad);
  5924. }
  5925.  
  5926. /*****/
  5927.  
  5928. static void
  5929. grad_save_gradient (gradient_t *grad,
  5930.             char       *filename)
  5931. {
  5932.   FILE           *file;
  5933.   int             num_segments;
  5934.   grad_segment_t *seg;
  5935.  
  5936.   g_assert (grad != NULL);
  5937.  
  5938.   if (!filename)
  5939.     {
  5940.       g_message ("grad_save_gradient(): "
  5941.                  "can not save gradient with NULL filename");
  5942.       return;
  5943.     }
  5944.  
  5945.   file = fopen (filename, "wb");
  5946.   if (!file)
  5947.     {
  5948.       g_message ("grad_save_gradient(): can't open \"%s\"", filename);
  5949.       return;
  5950.     }
  5951.  
  5952.   /* File format is:
  5953.    *
  5954.    *   GIMP Gradient
  5955.    *   number_of_segments
  5956.    *   left middle right r0 g0 b0 a0 r1 g1 b1 a1 type coloring
  5957.    *   left middle right r0 g0 b0 a0 r1 g1 b1 a1 type coloring
  5958.    *   ...
  5959.    */
  5960.  
  5961.   fprintf (file, "GIMP Gradient\n");
  5962.  
  5963.   /* Count number of segments */
  5964.   num_segments = 0;
  5965.   seg          = grad->segments;
  5966.  
  5967.   while (seg)
  5968.     {
  5969.       num_segments++;
  5970.       seg = seg->next;
  5971.     }
  5972.  
  5973.   /* Write rest of file */
  5974.   fprintf (file, "%d\n", num_segments);
  5975.  
  5976.   for (seg = grad->segments; seg; seg = seg->next)
  5977.     fprintf (file, "%f %f %f %f %f %f %f %f %f %f %f %d %d\n",
  5978.          seg->left, seg->middle, seg->right,
  5979.          seg->r0, seg->g0, seg->b0, seg->a0,
  5980.          seg->r1, seg->g1, seg->b1, seg->a1,
  5981.          (int) seg->type, (int) seg->color);
  5982.  
  5983.   fclose(file);
  5984.  
  5985.   grad->dirty = FALSE;
  5986. }
  5987.  
  5988. /*****/
  5989.  
  5990. static gradient_t *
  5991. grad_create_default_gradient (void)
  5992. {
  5993.   gradient_t *grad;
  5994.  
  5995.   grad = grad_new_gradient ();
  5996.   grad->segments = seg_new_segment ();
  5997.  
  5998.   return grad;
  5999. }
  6000.  
  6001. /*****/
  6002.  
  6003. static gint
  6004. grad_insert_in_gradients_list (gradient_t *grad)
  6005. {
  6006.   GSList     *tmp;
  6007.   gradient_t *g;
  6008.   gint        n;
  6009.  
  6010.   g_return_val_if_fail (grad != NULL, 0);
  6011.  
  6012.   /* We insert gradients in alphabetical order.  Find the index
  6013.    * of the gradient after which we will insert the current one.
  6014.    */
  6015.  
  6016.   g = NULL;
  6017.  
  6018.   for (tmp = gradients_list, n = 0; tmp; tmp = g_slist_next (tmp), n++)
  6019.     {
  6020.       g = tmp->data;
  6021.  
  6022.       if (strcmp (grad->name, g->name) <= 0)
  6023.     break; /* We found the one we want */
  6024.     }
  6025.  
  6026.   /* is there a gradient with this name already? */
  6027.   if (g && strcmp (grad->name, g->name) == 0)
  6028.     gradients_list_uniquefy_gradient_name (grad);
  6029.  
  6030.   num_gradients++;
  6031.   gradients_list = g_slist_insert (gradients_list, grad, n);
  6032.  
  6033.   return n;
  6034. }
  6035.  
  6036. static void
  6037. gradients_list_uniquefy_gradient_name (gradient_t *gradient)
  6038. {
  6039.   GSList     *list;
  6040.   GSList     *listg;
  6041.   gradient_t *gradg;
  6042.   gint        number = 1;
  6043.   gchar      *newname;
  6044.   gchar      *oldname;
  6045.   gchar      *ext;
  6046.   
  6047.   g_return_if_fail (gradient != NULL);
  6048.   
  6049.   for (list = gradients_list; list; list = g_slist_next (list))
  6050.     {
  6051.       gradg = (gradient_t *) list->data;
  6052.       
  6053.       if (! gradg->name)
  6054.     continue;
  6055.  
  6056.       if (gradient != gradg &&
  6057.       strcmp (gradient->name, gradg->name) == 0)
  6058.     {
  6059.       /* names conflict */
  6060.       oldname = gradient->name;
  6061.       newname = g_malloc (strlen (oldname) + 10); /* if this aint enough 
  6062.                              yer screwed */
  6063.       strcpy (newname, oldname);
  6064.       if ((ext = strrchr (newname, '#')))
  6065.         {
  6066.           number = atoi (ext + 1);
  6067.           
  6068.           if (&ext[(gint)(log10 (number) + 1)] !=
  6069.           &newname[strlen (newname) - 1])
  6070.         {
  6071.           number = 1;
  6072.           ext = &newname[strlen (newname)];
  6073.         }
  6074.         }
  6075.       else
  6076.         {
  6077.           number = 1;
  6078.           ext = &newname[strlen (newname)];
  6079.         }
  6080.       sprintf (ext, "#%d", number + 1);
  6081.       
  6082.       for (listg = gradients_list; listg; listg = g_slist_next (listg))
  6083.         {
  6084.           gradg = (gradient_t *) listg->data;
  6085.  
  6086.           if (! gradg->name)
  6087.         continue;
  6088.  
  6089.           if (gradient != gradg &&
  6090.           strcmp (newname,  gradg->name) == 0)
  6091.         {
  6092.           number++;
  6093.           sprintf (ext, "#%d", number+1);
  6094.           listg = gradients_list;
  6095.         }
  6096.         }
  6097.       
  6098.       g_free (gradient->name);
  6099.       gradient->name = newname;
  6100.  
  6101.       /*  should resort the list here  */
  6102.  
  6103.       return;
  6104.     }
  6105.     }
  6106. }
  6107.  
  6108. /*****/
  6109.  
  6110. static void
  6111. grad_dump_gradient (gradient_t *grad,
  6112.             FILE       *file)
  6113. {
  6114.   grad_segment_t *seg;
  6115.  
  6116.   g_return_if_fail (grad != NULL);
  6117.   g_return_if_fail (file != NULL);  
  6118.  
  6119.   fprintf (file, "Name: \"%s\"\n", grad->name);
  6120.   fprintf (file, "Dirty: %d\n", grad->dirty);
  6121.   fprintf (file, "Filename: \"%s\"\n", grad->filename);
  6122.  
  6123.   for (seg = grad->segments; seg; seg = seg->next)
  6124.     {
  6125.       fprintf (file, "%c%p | %f %f %f | %f %f %f %f | %f %f %f %f | %d %d | %p %p\n",
  6126.            (seg == grad->last_visited) ? '>' : ' ',
  6127.            seg,
  6128.            seg->left, seg->middle, seg->right,
  6129.            seg->r0, seg->g0, seg->b0, seg->a0,
  6130.            seg->r1, seg->g1, seg->b1, seg->a1,
  6131.            (int) seg->type,
  6132.            (int) seg->color,
  6133.            seg->prev, seg->next);
  6134.     }
  6135. }
  6136.  
  6137. /***** Segment functions *****/
  6138.  
  6139. static grad_segment_t *
  6140. seg_new_segment (void)
  6141. {
  6142.   grad_segment_t *seg;
  6143.  
  6144.   seg = g_new (grad_segment_t, 1);
  6145.  
  6146.   seg->left   = 0.0;
  6147.   seg->middle = 0.5;
  6148.   seg->right  = 1.0;
  6149.  
  6150.   seg->r0 = seg->g0 = seg->b0 = 0.0;
  6151.   seg->r1 = seg->g1 = seg->b1 = seg->a0 = seg->a1 = 1.0;
  6152.  
  6153.   seg->type  = GRAD_LINEAR;
  6154.   seg->color = GRAD_RGB;
  6155.  
  6156.   seg->prev = seg->next = NULL;
  6157.  
  6158.   return seg;
  6159. }
  6160.  
  6161. /*****/
  6162.  
  6163. static void
  6164. seg_free_segment (grad_segment_t *seg)
  6165. {
  6166.   g_assert (seg != NULL);
  6167.  
  6168.   g_free (seg);
  6169. }
  6170.  
  6171. static void
  6172. seg_free_segments (grad_segment_t *seg)
  6173. {
  6174.   grad_segment_t *tmp;
  6175.  
  6176.   g_assert (seg != NULL);
  6177.  
  6178.   while (seg)
  6179.     {
  6180.       tmp = seg->next;
  6181.       seg_free_segment (seg);
  6182.       seg = tmp;
  6183.     }
  6184. }
  6185.  
  6186. /*****/
  6187.  
  6188. static grad_segment_t *
  6189. seg_get_segment_at (gradient_t *grad,
  6190.             double      pos)
  6191. {
  6192.   grad_segment_t *seg;
  6193.  
  6194.   g_assert (grad != NULL);
  6195.  
  6196.   /* handle FP imprecision at the edges of the gradient */
  6197.   pos = CLAMP (pos, 0.0, 1.0);
  6198.  
  6199.   if (grad->last_visited)
  6200.     seg = grad->last_visited;
  6201.   else
  6202.     seg = grad->segments;
  6203.  
  6204.   while (seg)
  6205.     {
  6206.       if (pos >= seg->left)
  6207.     {
  6208.       if (pos <= seg->right)
  6209.         {
  6210.           grad->last_visited = seg; /* for speed */
  6211.           return seg;
  6212.         }
  6213.       else
  6214.         {
  6215.           seg = seg->next;
  6216.         }
  6217.     }
  6218.       else
  6219.     {
  6220.       seg = seg->prev;
  6221.     }
  6222.     }
  6223.  
  6224.   /* Oops: we should have found a segment, but we didn't */
  6225.   grad_dump_gradient (grad, stderr);
  6226.   gimp_fatal_error ("seg_get_segment_at(): "
  6227.                     "No matching segment for position %0.15f", pos);
  6228.  
  6229.   return NULL; /* To shut up -Wall */
  6230. }
  6231.  
  6232. /*****/
  6233.  
  6234. static grad_segment_t *
  6235. seg_get_last_segment (grad_segment_t *seg)
  6236. {
  6237.   if (!seg)
  6238.     return NULL;
  6239.  
  6240.   while (seg->next)
  6241.     seg = seg->next;
  6242.  
  6243.   return seg;
  6244. }
  6245.  
  6246. /*****/
  6247.  
  6248. static void
  6249. seg_get_closest_handle (gradient_t           *grad,
  6250.             double                pos,
  6251.             grad_segment_t      **seg,
  6252.             control_drag_mode_t  *handle)
  6253. {
  6254.   double l_delta, m_delta, r_delta;
  6255.  
  6256.   *seg = seg_get_segment_at (grad, pos);
  6257.  
  6258.   m_delta = fabs (pos - (*seg)->middle);
  6259.  
  6260.   if (pos < (*seg)->middle)
  6261.     {
  6262.       l_delta = fabs (pos - (*seg)->left);
  6263.  
  6264.       if (l_delta < m_delta)
  6265.     *handle = GRAD_DRAG_LEFT;
  6266.       else
  6267.     *handle = GRAD_DRAG_MIDDLE;
  6268.     }
  6269.   else
  6270.     {
  6271.       r_delta = fabs (pos - (*seg)->right);
  6272.  
  6273.       if (m_delta < r_delta)
  6274.     {
  6275.       *handle = GRAD_DRAG_MIDDLE;
  6276.     }
  6277.       else
  6278.     {
  6279.       *seg = (*seg)->next;
  6280.       *handle = GRAD_DRAG_LEFT;
  6281.     }
  6282.     }
  6283. }
  6284.  
  6285. /***** Calculation functions *****/
  6286.  
  6287. static double
  6288. calc_linear_factor (double middle,
  6289.             double pos)
  6290. {
  6291.   if (pos <= middle)
  6292.     {
  6293.       if (middle < EPSILON)
  6294.     return 0.0;
  6295.       else
  6296.     return 0.5 * pos / middle;
  6297.     }
  6298.   else
  6299.     {
  6300.       pos -= middle;
  6301.       middle = 1.0 - middle;
  6302.  
  6303.       if (middle < EPSILON)
  6304.     return 1.0;
  6305.       else
  6306.     return 0.5 + 0.5 * pos / middle;
  6307.     }
  6308. }
  6309.  
  6310. static double
  6311. calc_curved_factor (double middle,
  6312.             double pos)
  6313. {
  6314.   if (middle < EPSILON)
  6315.     middle = EPSILON;
  6316.  
  6317.   return pow(pos, log (0.5) / log (middle));
  6318. }
  6319.  
  6320. static double
  6321. calc_sine_factor (double middle,
  6322.           double pos)
  6323. {
  6324.   pos = calc_linear_factor (middle, pos);
  6325.  
  6326.   return (sin ((-G_PI / 2.0) + G_PI * pos) + 1.0) / 2.0;
  6327. }
  6328.  
  6329. static double
  6330. calc_sphere_increasing_factor (double middle,
  6331.                    double pos)
  6332. {
  6333.   pos = calc_linear_factor (middle, pos) - 1.0;
  6334.  
  6335.   return sqrt (1.0 - pos * pos); /* Works for convex increasing and concave decreasing */
  6336. }
  6337.  
  6338. static double
  6339. calc_sphere_decreasing_factor (double middle,
  6340.                    double pos)
  6341. {
  6342.   pos = calc_linear_factor (middle, pos);
  6343.  
  6344.   return 1.0 - sqrt(1.0 - pos * pos); /* Works for convex decreasing and concave increasing */
  6345. }
  6346.  
  6347.  
  6348. /***** Files and paths functions *****/
  6349.  
  6350. static gchar *
  6351. build_user_filename (gchar *name,
  6352.              gchar *path_str)
  6353. {
  6354.   GList *grad_path;
  6355.   gchar *grad_dir;
  6356.   gchar *filename;
  6357.  
  6358.   g_assert (name != NULL);
  6359.  
  6360.   if (!path_str)
  6361.     return NULL; /* Perhaps this is not a good idea */
  6362.  
  6363.   grad_path = gimp_path_parse (path_str, 16, TRUE, NULL);
  6364.   grad_dir  = gimp_path_get_user_writable_dir (grad_path);
  6365.   gimp_path_free (grad_path);
  6366.  
  6367.   if (!grad_dir)
  6368.     return NULL; /* Perhaps this is not a good idea */
  6369.  
  6370.   filename = g_strdup_printf ("%s%s", grad_dir, name);
  6371.  
  6372.   g_free (grad_dir);
  6373.  
  6374.   return filename;
  6375. }
  6376.